refactor: tabs
parent
53625976b8
commit
cd9f592c2e
|
@ -42,38 +42,57 @@ import { defineComponent, ref } from 'vue';
|
|||
export default defineComponent({
|
||||
setup() {
|
||||
return {
|
||||
activeKey: ref(1),
|
||||
activeKey: ref('2'),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
.card-container {
|
||||
background: #f5f5f5;
|
||||
overflow: hidden;
|
||||
padding: 24px;
|
||||
.card-container p {
|
||||
margin: 0;
|
||||
}
|
||||
.card-container > .ant-tabs-card > .ant-tabs-content {
|
||||
.card-container > .ant-tabs-card .ant-tabs-content {
|
||||
height: 120px;
|
||||
margin-top: -16px;
|
||||
}
|
||||
|
||||
.card-container > .ant-tabs-card > .ant-tabs-content > .ant-tabs-tabpane {
|
||||
background: #fff;
|
||||
.card-container > .ant-tabs-card .ant-tabs-content > .ant-tabs-tabpane {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.card-container > .ant-tabs-card > .ant-tabs-bar {
|
||||
border-color: #fff;
|
||||
}
|
||||
|
||||
.card-container > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab {
|
||||
border-color: transparent;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.card-container > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active {
|
||||
border-color: #fff;
|
||||
background: #fff;
|
||||
}
|
||||
.card-container > .ant-tabs-card > .ant-tabs-nav::before {
|
||||
display: none;
|
||||
}
|
||||
.card-container > .ant-tabs-card .ant-tabs-tab,
|
||||
[data-theme='compact'] .card-container > .ant-tabs-card .ant-tabs-tab {
|
||||
background: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
.card-container > .ant-tabs-card .ant-tabs-tab-active,
|
||||
[data-theme='compact'] .card-container > .ant-tabs-card .ant-tabs-tab-active {
|
||||
background: #fff;
|
||||
border-color: #fff;
|
||||
}
|
||||
#components-tabs-demo-card-top .code-box-demo {
|
||||
padding: 24px;
|
||||
overflow: hidden;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
[data-theme='compact'] .card-container > .ant-tabs-card .ant-tabs-content {
|
||||
height: 120px;
|
||||
margin-top: -8px;
|
||||
}
|
||||
[data-theme='dark'] .card-container > .ant-tabs-card .ant-tabs-tab {
|
||||
background: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
[data-theme='dark'] #components-tabs-demo-card-top .code-box-demo {
|
||||
background: #000;
|
||||
}
|
||||
[data-theme='dark'] .card-container > .ant-tabs-card .ant-tabs-content > .ant-tabs-tabpane {
|
||||
background: #141414;
|
||||
}
|
||||
[data-theme='dark'] .card-container > .ant-tabs-card .ant-tabs-tab-active {
|
||||
background: #141414;
|
||||
border-color: #141414;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import type { Tab } from './interface';
|
||||
import type { PropType, InjectionKey } from 'vue';
|
||||
import { provide, inject, defineComponent } from 'vue';
|
||||
import type { PropType, InjectionKey, Ref } from 'vue';
|
||||
import { provide, inject, defineComponent, toRefs, ref } from 'vue';
|
||||
|
||||
export interface TabContextProps {
|
||||
tabs: Tab[];
|
||||
prefixCls: string;
|
||||
tabs: Ref<Tab[]>;
|
||||
prefixCls: Ref<string>;
|
||||
}
|
||||
|
||||
const TabsContextKey: InjectionKey<TabContextProps> = Symbol('tabsContextKey');
|
||||
|
@ -14,7 +14,7 @@ export const useProvideTabs = (props: TabContextProps) => {
|
|||
};
|
||||
|
||||
export const useInjectTabs = () => {
|
||||
return inject(TabsContextKey, { tabs: [], prefixCls: undefined });
|
||||
return inject(TabsContextKey, { tabs: ref([]), prefixCls: ref() });
|
||||
};
|
||||
|
||||
const TabsContextProvider = defineComponent({
|
||||
|
@ -25,7 +25,7 @@ const TabsContextProvider = defineComponent({
|
|||
prefixCls: { type: String, default: undefined },
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
useProvideTabs(props);
|
||||
useProvideTabs(toRefs(props));
|
||||
return () => slots.default?.();
|
||||
},
|
||||
});
|
||||
|
|
|
@ -16,7 +16,7 @@ export interface OperationNodeProps {
|
|||
tabs: Tab[];
|
||||
rtl: boolean;
|
||||
tabBarGutter?: number;
|
||||
activeKey: string;
|
||||
activeKey: Key;
|
||||
mobile: boolean;
|
||||
moreIcon?: VueNode;
|
||||
moreTransitionName?: string;
|
||||
|
@ -34,7 +34,7 @@ export default defineComponent({
|
|||
tabs: { type: Object as PropType<Tab[]> },
|
||||
rtl: { type: Boolean },
|
||||
tabBarGutter: { type: Number },
|
||||
activeKey: { type: String },
|
||||
activeKey: { type: [String, Number] },
|
||||
mobile: { type: Boolean },
|
||||
moreIcon: PropTypes.any,
|
||||
moreTransitionName: { type: String },
|
||||
|
@ -47,7 +47,7 @@ export default defineComponent({
|
|||
setup(props, { attrs, slots }) {
|
||||
// ======================== Dropdown ========================
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selectedKey, setSelectedKey] = useState<string>(null);
|
||||
const [selectedKey, setSelectedKey] = useState<Key>(null);
|
||||
const selectOffset = (offset: -1 | 1) => {
|
||||
const enabledTabs = props.tabs.filter(tab => !tab.disabled);
|
||||
let selectedIndex = enabledTabs.findIndex(tab => tab.key === selectedKey.value) || 0;
|
||||
|
|
|
@ -32,7 +32,7 @@ const tabNavListProps = () => {
|
|||
return {
|
||||
id: { type: String },
|
||||
tabPosition: { type: String as PropType<TabPosition> },
|
||||
activeKey: { type: String },
|
||||
activeKey: { type: [String, Number] },
|
||||
rtl: { type: Boolean },
|
||||
panes: PropTypes.any,
|
||||
animated: { type: Object as PropType<AnimatedConfig>, default: undefined as AnimatedConfig },
|
||||
|
@ -66,7 +66,7 @@ export default defineComponent({
|
|||
slots: ['panes', 'moreIcon', 'extra'],
|
||||
emits: ['tabClick', 'tabScroll'],
|
||||
setup(props, { attrs, slots }) {
|
||||
const tabsContext = useInjectTabs();
|
||||
const { tabs, prefixCls } = useInjectTabs();
|
||||
const tabsWrapperRef = ref<HTMLDivElement>();
|
||||
const tabListRef = ref<HTMLDivElement>();
|
||||
const operationsRef = ref<{ $el: HTMLDivElement }>();
|
||||
|
@ -98,15 +98,10 @@ export default defineComponent({
|
|||
const [addHeight, setAddHeight] = useState<number>(0);
|
||||
|
||||
const [tabSizes, setTabSizes] = useRafState<TabSizeMap>(new Map());
|
||||
const tabOffsets = useOffsets(
|
||||
computed(() => tabsContext.tabs),
|
||||
tabSizes,
|
||||
);
|
||||
const tabOffsets = useOffsets(tabs, tabSizes);
|
||||
|
||||
// ========================== Util =========================
|
||||
const operationsHiddenClassName = computed(
|
||||
() => `${tabsContext.prefixCls}-nav-operations-hidden`,
|
||||
);
|
||||
const operationsHiddenClassName = computed(() => `${prefixCls.value}-nav-operations-hidden`);
|
||||
|
||||
const transformMin = ref(0);
|
||||
const transformMax = ref(0);
|
||||
|
@ -261,15 +256,15 @@ export default defineComponent({
|
|||
mergedBasicSize = basicSize - addSize;
|
||||
}
|
||||
|
||||
const { tabs } = tabsContext;
|
||||
if (!tabs.length) {
|
||||
const tabsVal = tabs.value;
|
||||
if (!tabsVal.length) {
|
||||
[visibleStart.value, visibleEnd.value] = [0, 0];
|
||||
}
|
||||
|
||||
const len = tabs.length;
|
||||
const len = tabsVal.length;
|
||||
let endIndex = len;
|
||||
for (let i = 0; i < len; i += 1) {
|
||||
const offset = tabOffsets.value.get(tabs[i].key) || DEFAULT_SIZE;
|
||||
const offset = tabOffsets.value.get(tabsVal[i].key) || DEFAULT_SIZE;
|
||||
if (offset[position] + offset[unit] > transformSize + mergedBasicSize) {
|
||||
endIndex = i - 1;
|
||||
break;
|
||||
|
@ -278,7 +273,7 @@ export default defineComponent({
|
|||
|
||||
let startIndex = 0;
|
||||
for (let i = len - 1; i >= 0; i -= 1) {
|
||||
const offset = tabOffsets.value.get(tabs[i].key) || DEFAULT_SIZE;
|
||||
const offset = tabOffsets.value.get(tabsVal[i].key) || DEFAULT_SIZE;
|
||||
if (offset[position] < transformSize) {
|
||||
startIndex = i + 1;
|
||||
break;
|
||||
|
@ -319,7 +314,7 @@ export default defineComponent({
|
|||
// Update buttons records
|
||||
setTabSizes(() => {
|
||||
const newSizes: TabSizeMap = new Map();
|
||||
tabsContext.tabs.forEach(({ key }) => {
|
||||
tabs.value.forEach(({ key }) => {
|
||||
const btnRef = getBtnRef(key).value;
|
||||
const btnNode = (btnRef as any).$el || btnRef;
|
||||
if (btnNode) {
|
||||
|
@ -337,8 +332,8 @@ export default defineComponent({
|
|||
|
||||
// ======================== Dropdown =======================
|
||||
const hiddenTabs = computed(() => [
|
||||
...tabsContext.tabs.slice(0, visibleStart.value),
|
||||
...tabsContext.tabs.slice(visibleEnd.value + 1),
|
||||
...tabs.value.slice(0, visibleStart.value),
|
||||
...tabs.value.slice(visibleEnd.value + 1),
|
||||
]);
|
||||
|
||||
// =================== Link & Operations ===================
|
||||
|
@ -385,7 +380,7 @@ export default defineComponent({
|
|||
);
|
||||
|
||||
watch(
|
||||
[() => props.rtl, () => props.tabBarGutter, () => props.activeKey, () => tabsContext.tabs],
|
||||
[() => props.rtl, () => props.tabBarGutter, () => props.activeKey, () => tabs.value],
|
||||
() => {
|
||||
onListHolderResize();
|
||||
},
|
||||
|
@ -406,7 +401,6 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
return () => {
|
||||
const { prefixCls, tabs } = tabsContext;
|
||||
const {
|
||||
id,
|
||||
animated,
|
||||
|
@ -420,9 +414,10 @@ export default defineComponent({
|
|||
onTabClick,
|
||||
} = props;
|
||||
const { class: className, style } = attrs;
|
||||
const pre = prefixCls.value;
|
||||
// ========================= Render ========================
|
||||
const hasDropdown = !!hiddenTabs.value.length;
|
||||
const wrapPrefix = `${prefixCls}-nav-wrap`;
|
||||
const wrapPrefix = `${pre}-nav-wrap`;
|
||||
let pingLeft: boolean;
|
||||
let pingRight: boolean;
|
||||
let pingTop: boolean;
|
||||
|
@ -450,12 +445,12 @@ export default defineComponent({
|
|||
typeof tabBarGutter === 'number' ? `${tabBarGutter}px` : tabBarGutter;
|
||||
}
|
||||
|
||||
const tabNodes = tabs.map((tab, i) => {
|
||||
const tabNodes = tabs.value.map((tab, i) => {
|
||||
const { key } = tab;
|
||||
return (
|
||||
<TabNode
|
||||
id={id}
|
||||
prefixCls={prefixCls}
|
||||
prefixCls={pre}
|
||||
key={key}
|
||||
tab={tab}
|
||||
/* first node should not have margin left */
|
||||
|
@ -492,14 +487,14 @@ export default defineComponent({
|
|||
<div
|
||||
ref={ref}
|
||||
role="tablist"
|
||||
class={classNames(`${prefixCls}-nav`, className)}
|
||||
class={classNames(`${pre}-nav`, className)}
|
||||
style={style}
|
||||
onKeydown={() => {
|
||||
// No need animation when use keyboard
|
||||
doLockAnimation();
|
||||
}}
|
||||
>
|
||||
<ExtraContent position="left" extra={extra} prefixCls={prefixCls} />
|
||||
<ExtraContent position="left" extra={extra} prefixCls={pre} />
|
||||
|
||||
<ResizeObserver onResize={onListHolderResize}>
|
||||
<div
|
||||
|
@ -514,7 +509,7 @@ export default defineComponent({
|
|||
<ResizeObserver onResize={onListHolderResize}>
|
||||
<div
|
||||
ref={tabListRef}
|
||||
class={`${prefixCls}-nav-list`}
|
||||
class={`${pre}-nav-list`}
|
||||
style={{
|
||||
transform: `translate(${transformLeft.value}px, ${transformTop.value}px)`,
|
||||
transition: lockAnimation.value ? 'none' : undefined,
|
||||
|
@ -523,7 +518,7 @@ export default defineComponent({
|
|||
{tabNodes}
|
||||
<AddButton
|
||||
ref={innerAddButtonRef}
|
||||
prefixCls={prefixCls}
|
||||
prefixCls={pre}
|
||||
locale={locale}
|
||||
editable={editable}
|
||||
style={{
|
||||
|
@ -533,8 +528,8 @@ export default defineComponent({
|
|||
/>
|
||||
|
||||
<div
|
||||
class={classNames(`${prefixCls}-ink-bar`, {
|
||||
[`${prefixCls}-ink-bar-animated`]: animated.inkBar,
|
||||
class={classNames(`${pre}-ink-bar`, {
|
||||
[`${pre}-ink-bar-animated`]: animated.inkBar,
|
||||
})}
|
||||
style={inkStyle.value}
|
||||
/>
|
||||
|
@ -546,12 +541,12 @@ export default defineComponent({
|
|||
<OperationNode
|
||||
{...props}
|
||||
ref={operationsRef}
|
||||
prefixCls={prefixCls}
|
||||
prefixCls={pre}
|
||||
tabs={hiddenTabs.value}
|
||||
class={!hasDropdown && operationsHiddenClassName.value}
|
||||
/>
|
||||
|
||||
<ExtraContent position="right" extra={extra} prefixCls={prefixCls} />
|
||||
<ExtraContent position="right" extra={extra} prefixCls={pre} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { defineComponent, ref, watch, computed } from 'vue';
|
||||
import type { CSSProperties } from 'vue';
|
||||
import type { VueNode } from '../../../_util/type';
|
||||
import type { VueNode, Key } from '../../../_util/type';
|
||||
import PropTypes from '../../../_util/vue-types';
|
||||
|
||||
export interface TabPaneProps {
|
||||
|
@ -12,7 +12,7 @@ export interface TabPaneProps {
|
|||
|
||||
// Pass by TabPaneList
|
||||
prefixCls?: string;
|
||||
tabKey?: string;
|
||||
tabKey?: Key;
|
||||
id?: string;
|
||||
animated?: boolean;
|
||||
active?: boolean;
|
||||
|
@ -33,7 +33,7 @@ export default defineComponent({
|
|||
|
||||
// Pass by TabPaneList
|
||||
prefixCls: { type: String },
|
||||
tabKey: { type: String },
|
||||
tabKey: { type: [String, Number] },
|
||||
id: { type: String },
|
||||
},
|
||||
slots: ['closeIcon', 'tab'],
|
||||
|
|
|
@ -25,22 +25,20 @@ export default defineComponent({
|
|||
destroyInactiveTabPane: { type: Boolean },
|
||||
},
|
||||
setup(props) {
|
||||
const tabsContext = useInjectTabs();
|
||||
const { tabs, prefixCls } = useInjectTabs();
|
||||
return () => {
|
||||
const { id, activeKey, animated, tabPosition, rtl, destroyInactiveTabPane } = props;
|
||||
const { prefixCls, tabs } = tabsContext;
|
||||
const tabPaneAnimated = animated.tabPane;
|
||||
|
||||
const activeIndex = tabs.findIndex(tab => tab.key === activeKey);
|
||||
|
||||
const pre = prefixCls.value;
|
||||
const activeIndex = tabs.value.findIndex(tab => tab.key === activeKey);
|
||||
return (
|
||||
<div class={`${prefixCls}-content-holder`}>
|
||||
<div class={`${pre}-content-holder`}>
|
||||
<div
|
||||
class={[
|
||||
`${prefixCls}-content`,
|
||||
`${prefixCls}-content-${tabPosition}`,
|
||||
`${pre}-content`,
|
||||
`${pre}-content-${tabPosition}`,
|
||||
{
|
||||
[`${prefixCls}-content-animated`]: tabPaneAnimated,
|
||||
[`${pre}-content-animated`]: tabPaneAnimated,
|
||||
},
|
||||
]}
|
||||
style={
|
||||
|
@ -49,10 +47,10 @@ export default defineComponent({
|
|||
: null
|
||||
}
|
||||
>
|
||||
{tabs.map(tab => {
|
||||
{tabs.value.map(tab => {
|
||||
return cloneElement(tab.node, {
|
||||
key: tab.key,
|
||||
prefixCls,
|
||||
prefixCls: pre,
|
||||
tabKey: tab.key,
|
||||
id,
|
||||
animated: tabPaneAnimated,
|
||||
|
|
|
@ -21,7 +21,8 @@ import classNames from '../../_util/classNames';
|
|||
import { CloseOutlined, PlusOutlined } from '@ant-design/icons-vue';
|
||||
import devWarning from '../../vc-util/devWarning';
|
||||
import type { SizeType } from '../../config-provider';
|
||||
import TabsContextProvider from './TabContext';
|
||||
import { useProvideTabs } from './TabContext';
|
||||
import type { Key } from '../../_util/type';
|
||||
|
||||
export type TabsType = 'line' | 'card' | 'editable-card';
|
||||
export type TabsPosition = 'top' | 'right' | 'bottom' | 'left';
|
||||
|
@ -34,8 +35,8 @@ export const tabsProps = () => {
|
|||
prefixCls: { type: String },
|
||||
id: { type: String },
|
||||
|
||||
activeKey: { type: String },
|
||||
defaultActiveKey: { type: String },
|
||||
activeKey: { type: [String, Number], required: true },
|
||||
defaultActiveKey: { type: [String, Number] },
|
||||
direction: { type: String as PropType<'ltr' | 'rtl'> },
|
||||
animated: { type: [Boolean, Object] as PropType<boolean | AnimatedConfig> },
|
||||
renderTabBar: { type: Function as PropType<RenderTabBar> },
|
||||
|
@ -50,12 +51,12 @@ export const tabsProps = () => {
|
|||
centered: Boolean,
|
||||
onEdit: {
|
||||
type: Function as PropType<
|
||||
(e: MouseEvent | KeyboardEvent | string, action: 'add' | 'remove') => void
|
||||
(e: MouseEvent | KeyboardEvent | Key, action: 'add' | 'remove') => void
|
||||
>,
|
||||
},
|
||||
onChange: { type: Function as PropType<(activeKey: string) => void> },
|
||||
onChange: { type: Function as PropType<(activeKey: Key) => void> },
|
||||
onTabClick: {
|
||||
type: Function as PropType<(activeKey: string, e: KeyboardEvent | MouseEvent) => void>,
|
||||
type: Function as PropType<(activeKey: Key, e: KeyboardEvent | MouseEvent) => void>,
|
||||
},
|
||||
onTabScroll: { type: Function as PropType<OnTabScroll> },
|
||||
|
||||
|
@ -78,7 +79,7 @@ function parseTabList(children: any[]): Tab[] {
|
|||
props[camelize(k)] = v;
|
||||
}
|
||||
const slots = node.children || {};
|
||||
const key = node.key !== undefined ? String(node.key) : undefined;
|
||||
const key = node.key !== undefined ? node.key : undefined;
|
||||
const {
|
||||
tab = slots.tab,
|
||||
disabled,
|
||||
|
@ -159,7 +160,7 @@ const InternalTabs = defineComponent({
|
|||
});
|
||||
|
||||
// ====================== Active Key ======================
|
||||
const [mergedActiveKey, setMergedActiveKey] = useMergedState<string>(() => props.tabs[0]?.key, {
|
||||
const [mergedActiveKey, setMergedActiveKey] = useMergedState<Key>(() => props.tabs[0]?.key, {
|
||||
value: computed(() => props.activeKey),
|
||||
defaultValue: props.defaultActiveKey,
|
||||
});
|
||||
|
@ -171,7 +172,7 @@ const InternalTabs = defineComponent({
|
|||
let newActiveIndex = props.tabs.findIndex(tab => tab.key === mergedActiveKey.value);
|
||||
if (newActiveIndex === -1) {
|
||||
newActiveIndex = Math.max(0, Math.min(activeIndex.value, props.tabs.length - 1));
|
||||
setMergedActiveKey(props.tabs[newActiveIndex]?.key);
|
||||
mergedActiveKey.value = props.tabs[newActiveIndex]?.key;
|
||||
}
|
||||
setActiveIndex(newActiveIndex);
|
||||
});
|
||||
|
@ -197,30 +198,30 @@ const InternalTabs = defineComponent({
|
|||
});
|
||||
|
||||
// ======================== Events ========================
|
||||
const onInternalTabClick = (key: string, e: MouseEvent | KeyboardEvent) => {
|
||||
const onInternalTabClick = (key: Key, e: MouseEvent | KeyboardEvent) => {
|
||||
props.onTabClick?.(key, e);
|
||||
|
||||
setMergedActiveKey(key);
|
||||
props.onChange?.(key);
|
||||
};
|
||||
|
||||
useProvideTabs({
|
||||
tabs: computed(() => props.tabs),
|
||||
prefixCls,
|
||||
});
|
||||
|
||||
return () => {
|
||||
const {
|
||||
id,
|
||||
type,
|
||||
activeKey,
|
||||
defaultActiveKey,
|
||||
tabBarGutter,
|
||||
tabBarStyle,
|
||||
locale,
|
||||
destroyInactiveTabPane,
|
||||
renderTabBar,
|
||||
onChange,
|
||||
onTabClick,
|
||||
onTabScroll,
|
||||
hideAdd,
|
||||
centered,
|
||||
...restProps
|
||||
} = props;
|
||||
// ======================== Render ========================
|
||||
const sharedProps = {
|
||||
|
@ -274,34 +275,31 @@ const InternalTabs = defineComponent({
|
|||
const pre = prefixCls.value;
|
||||
|
||||
return (
|
||||
<TabsContextProvider tabs={props.tabs} prefixCls={pre}>
|
||||
<div
|
||||
{...attrs}
|
||||
id={id}
|
||||
class={classNames(
|
||||
pre,
|
||||
`${pre}-${mergedTabPosition.value}`,
|
||||
{
|
||||
[`${pre}-${size}`]: size.value,
|
||||
[`${pre}-card`]: ['card', 'editable-card'].includes(type as string),
|
||||
[`${pre}-editable-card`]: type === 'editable-card',
|
||||
[`${pre}-centered`]: centered,
|
||||
[`${pre}-mobile`]: mobile.value,
|
||||
[`${pre}-editable`]: type === 'editable-card',
|
||||
[`${pre}-rtl`]: rtl.value,
|
||||
},
|
||||
attrs.class,
|
||||
)}
|
||||
{...restProps}
|
||||
>
|
||||
{tabNavBar}
|
||||
<TabPanelList
|
||||
destroyInactiveTabPane={destroyInactiveTabPane}
|
||||
{...sharedProps}
|
||||
animated={mergedAnimated.value}
|
||||
/>
|
||||
</div>
|
||||
</TabsContextProvider>
|
||||
<div
|
||||
{...attrs}
|
||||
id={id}
|
||||
class={classNames(
|
||||
pre,
|
||||
`${pre}-${mergedTabPosition.value}`,
|
||||
{
|
||||
[`${pre}-${size}`]: size.value,
|
||||
[`${pre}-card`]: ['card', 'editable-card'].includes(type as string),
|
||||
[`${pre}-editable-card`]: type === 'editable-card',
|
||||
[`${pre}-centered`]: centered,
|
||||
[`${pre}-mobile`]: mobile.value,
|
||||
[`${pre}-editable`]: type === 'editable-card',
|
||||
[`${pre}-rtl`]: rtl.value,
|
||||
},
|
||||
attrs.class,
|
||||
)}
|
||||
>
|
||||
{tabNavBar}
|
||||
<TabPanelList
|
||||
destroyInactiveTabPane={destroyInactiveTabPane}
|
||||
{...sharedProps}
|
||||
animated={mergedAnimated.value}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
},
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import supportsPassive from 'ant-design-vue/es/_util/supportsPassive';
|
||||
import type { Ref } from 'vue';
|
||||
import { ref, onBeforeUnmount, onMounted } from 'vue';
|
||||
import useState from '../../../_util/hooks/useState';
|
||||
|
@ -9,7 +10,6 @@ const MIN_SWIPE_DISTANCE = 0.1;
|
|||
const STOP_SWIPE_DISTANCE = 0.01;
|
||||
const REFRESH_INTERVAL = 20;
|
||||
const SPEED_OFF_MULTIPLE = 0.995 ** REFRESH_INTERVAL;
|
||||
|
||||
// ================================= Hook =================================
|
||||
export default function useTouchMove(
|
||||
domRef: Ref<HTMLDivElement>,
|
||||
|
@ -131,7 +131,11 @@ export default function useTouchMove(
|
|||
|
||||
// No need to clean up since element removed
|
||||
domRef.value.addEventListener('touchstart', onProxyTouchStart, { passive: false });
|
||||
domRef.value.addEventListener('wheel', onProxyWheel);
|
||||
domRef.value.addEventListener(
|
||||
'wheel',
|
||||
onProxyWheel,
|
||||
supportsPassive ? { passive: true } : false,
|
||||
);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
|
|
|
@ -15,7 +15,7 @@ export type TabOffsetMap = Map<Key, TabOffset>;
|
|||
export type TabPosition = 'left' | 'right' | 'top' | 'bottom';
|
||||
|
||||
export interface Tab extends TabPaneProps {
|
||||
key: string;
|
||||
key: Key;
|
||||
node: VueNode;
|
||||
}
|
||||
|
||||
|
@ -28,10 +28,7 @@ export interface TabsLocale {
|
|||
}
|
||||
|
||||
export interface EditableConfig {
|
||||
onEdit: (
|
||||
type: 'add' | 'remove',
|
||||
info: { key?: string; event: MouseEvent | KeyboardEvent },
|
||||
) => void;
|
||||
onEdit: (type: 'add' | 'remove', info: { key?: Key; event: MouseEvent | KeyboardEvent }) => void;
|
||||
showAdd?: boolean;
|
||||
removeIcon?: () => VueNode;
|
||||
addIcon?: () => VueNode;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// debugger tsx
|
||||
import Demo from '../../components/tabs/demo/basic.vue';
|
||||
import Demo from '../../components/tabs/demo/card-top.vue';
|
||||
|
||||
export default {
|
||||
render() {
|
||||
|
|
Loading…
Reference in New Issue