Skip to content

Commit 56e59aa

Browse files
feat: support overwrite the more tabs dropdown props (#396)
1 parent b68f85a commit 56e59aa

File tree

4 files changed

+53
-13
lines changed

4 files changed

+53
-13
lines changed

src/TabNavList/OperationNode.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Menu, { MenuItem } from 'rc-menu';
66
import Dropdown from 'rc-dropdown';
77
import type { Tab, TabsLocale, EditableConfig } from '../interface';
88
import AddButton from './AddButton';
9+
import type { DropdownProps } from 'rc-dropdown/lib/Dropdown';
910

1011
export interface OperationNodeProps {
1112
prefixCls: string;
@@ -19,6 +20,7 @@ export interface OperationNodeProps {
1920
mobile: boolean;
2021
moreIcon?: React.ReactNode;
2122
moreTransitionName?: string;
23+
moreTabsDropdownProps?: Partial<DropdownProps>;
2224
editable?: EditableConfig;
2325
locale?: TabsLocale;
2426
onTabClick: (key: React.Key, e: React.MouseEvent | React.KeyboardEvent) => void;
@@ -39,6 +41,7 @@ function OperationNode(
3941
tabBarGutter,
4042
rtl,
4143
onTabClick,
44+
moreTabsDropdownProps,
4245
}: OperationNodeProps,
4346
ref: React.Ref<HTMLDivElement>,
4447
) {
@@ -65,7 +68,7 @@ function OperationNode(
6568
selectedKeys={[selectedKey]}
6669
aria-label={dropdownAriaLabel !== undefined ? dropdownAriaLabel : 'expanded dropdown'}
6770
>
68-
{tabs.map(tab => (
71+
{tabs.map((tab) => (
6972
<MenuItem
7073
key={tab.key}
7174
id={`${popupId}-${tab.key}`}
@@ -80,8 +83,8 @@ function OperationNode(
8083
);
8184

8285
function selectOffset(offset: -1 | 1) {
83-
const enabledTabs = tabs.filter(tab => !tab.disabled);
84-
let selectedIndex = enabledTabs.findIndex(tab => tab.key === selectedKey) || 0;
86+
const enabledTabs = tabs.filter((tab) => !tab.disabled);
87+
let selectedIndex = enabledTabs.findIndex((tab) => tab.key === selectedKey) || 0;
8588
const len = enabledTabs.length;
8689

8790
for (let i = 0; i < len; i += 1) {
@@ -149,7 +152,7 @@ function OperationNode(
149152
}
150153

151154
const overlayClassName = classNames({
152-
[`${dropdownPrefix}-rtl`]: rtl
155+
[`${dropdownPrefix}-rtl`]: rtl,
153156
});
154157

155158
const moreNode: React.ReactElement = mobile ? null : (
@@ -163,6 +166,7 @@ function OperationNode(
163166
overlayClassName={overlayClassName}
164167
mouseEnterDelay={0.1}
165168
mouseLeaveDelay={0.1}
169+
{...moreTabsDropdownProps}
166170
>
167171
<button
168172
type="button"

src/TabNavList/index.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import useTouchMove from '../hooks/useTouchMove';
2525
import useRefs from '../hooks/useRefs';
2626
import AddButton from './AddButton';
2727
import useSyncState from '../hooks/useSyncState';
28+
import type { DropdownProps } from 'rc-dropdown/lib/Dropdown';
2829

2930
export interface TabNavListProps {
3031
id: string;
@@ -36,6 +37,7 @@ export interface TabNavListProps {
3637
extra?: TabBarExtraContent;
3738
editable?: EditableConfig;
3839
moreIcon?: React.ReactNode;
40+
moreTabsDropdownProps?: Partial<DropdownProps>;
3941
moreTransitionName?: string;
4042
mobile: boolean;
4143
tabBarGutter?: number;
@@ -89,6 +91,7 @@ function TabNavList(props: TabNavListProps, ref: React.Ref<HTMLDivElement>) {
8991
children,
9092
onTabClick,
9193
onTabScroll,
94+
moreTabsDropdownProps,
9295
} = props;
9396
const tabsWrapperRef = useRef<HTMLDivElement>();
9497
const tabListRef = useRef<HTMLDivElement>();
@@ -162,7 +165,7 @@ function TabNavList(props: TabNavListProps, ref: React.Ref<HTMLDivElement>) {
162165

163166
useTouchMove(tabsWrapperRef, (offsetX, offsetY) => {
164167
function doMove(setState: React.Dispatch<React.SetStateAction<number>>, offset: number) {
165-
setState(value => {
168+
setState((value) => {
166169
const newValue = alignInRange(value + offset);
167170

168171
return newValue;
@@ -269,7 +272,7 @@ function TabNavList(props: TabNavListProps, ref: React.Ref<HTMLDivElement>) {
269272
{ ...props, tabs },
270273
);
271274

272-
const tabNodes: React.ReactElement[] = tabs.map(tab => {
275+
const tabNodes: React.ReactElement[] = tabs.map((tab) => {
273276
const { key } = tab;
274277
return (
275278
<TabNode
@@ -286,7 +289,7 @@ function TabNavList(props: TabNavListProps, ref: React.Ref<HTMLDivElement>) {
286289
renderWrapper={children}
287290
removeAriaLabel={locale?.removeAriaLabel}
288291
ref={getBtnRef(key)}
289-
onClick={e => {
292+
onClick={(e) => {
290293
onTabClick(key, e);
291294
}}
292295
onRemove={() => {
@@ -398,7 +401,7 @@ function TabNavList(props: TabNavListProps, ref: React.Ref<HTMLDivElement>) {
398401
// Should recalculate when rtl changed
399402
useEffect(() => {
400403
onListHolderResize();
401-
}, [rtl, tabBarGutter, activeKey, tabs.map(tab => tab.key).join('_')]);
404+
}, [rtl, tabBarGutter, activeKey, tabs.map((tab) => tab.key).join('_')]);
402405

403406
// ========================= Render ========================
404407
const hasDropdown = !!hiddenTabs.length;
@@ -478,6 +481,7 @@ function TabNavList(props: TabNavListProps, ref: React.Ref<HTMLDivElement>) {
478481
ref={operationsRef}
479482
prefixCls={prefixCls}
480483
tabs={hiddenTabs}
484+
moreTabsDropdownProps={moreTabsDropdownProps}
481485
className={!hasDropdown && operationsHiddenClassName}
482486
/>
483487

src/Tabs.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import type {
2020
TabBarExtraContent,
2121
} from './interface';
2222
import TabContext from './TabContext';
23+
import type { DropdownProps } from 'rc-dropdown/lib/Dropdown';
2324

2425
/**
2526
* Should added antd:
@@ -51,6 +52,7 @@ export interface TabsProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'o
5152
tabBarStyle?: React.CSSProperties;
5253
tabPosition?: TabPosition;
5354
destroyInactiveTabPane?: boolean;
55+
moreTabsDropdownProps?: Partial<DropdownProps>;
5456

5557
onChange?: (activeKey: string) => void;
5658
onTabClick?: (activeKey: string, e: React.KeyboardEvent | React.MouseEvent) => void;
@@ -81,7 +83,7 @@ function parseTabList(children: React.ReactNode): Tab[] {
8183

8284
return null;
8385
})
84-
.filter(tab => tab);
86+
.filter((tab) => tab);
8587
}
8688

8789
function Tabs(
@@ -106,6 +108,7 @@ function Tabs(
106108
moreIcon,
107109
moreTransitionName,
108110
destroyInactiveTabPane,
111+
moreTabsDropdownProps,
109112
renderTabBar,
110113
onChange,
111114
onTabClick,
@@ -149,18 +152,18 @@ function Tabs(
149152
defaultValue: defaultActiveKey,
150153
});
151154
const [activeIndex, setActiveIndex] = useState(() =>
152-
tabs.findIndex(tab => tab.key === mergedActiveKey),
155+
tabs.findIndex((tab) => tab.key === mergedActiveKey),
153156
);
154157

155158
// Reset active key if not exist anymore
156159
useEffect(() => {
157-
let newActiveIndex = tabs.findIndex(tab => tab.key === mergedActiveKey);
160+
let newActiveIndex = tabs.findIndex((tab) => tab.key === mergedActiveKey);
158161
if (newActiveIndex === -1) {
159162
newActiveIndex = Math.max(0, Math.min(activeIndex, tabs.length - 1));
160163
setMergedActiveKey(tabs[newActiveIndex]?.key);
161164
}
162165
setActiveIndex(newActiveIndex);
163-
}, [tabs.map(tab => tab.key).join('_'), mergedActiveKey, activeIndex]);
166+
}, [tabs.map((tab) => tab.key).join('_'), mergedActiveKey, activeIndex]);
164167

165168
// ===================== Accessibility ====================
166169
const [mergedId, setMergedId] = useMergedState(null, {
@@ -212,6 +215,7 @@ function Tabs(
212215
extra: tabBarExtraContent,
213216
style: tabBarStyle,
214217
panes: children,
218+
moreTabsDropdownProps,
215219
};
216220

217221
if (renderTabBar) {

tests/operation-overflow.test.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe('Tabs.Operation-Overflow', () => {
1515

1616
function btnOffsetPosition() {
1717
const btn = this as HTMLButtonElement;
18-
const btnList = [...btn.parentNode.childNodes].filter(ele =>
18+
const btnList = [...btn.parentNode.childNodes].filter((ele) =>
1919
(ele as HTMLElement).className.includes('rc-tabs-tab'),
2020
);
2121
const index = btnList.indexOf(btn);
@@ -62,4 +62,32 @@ describe('Tabs.Operation-Overflow', () => {
6262

6363
jest.useRealTimers();
6464
});
65+
66+
it('moreTabsDropdownProps trigger click', () => {
67+
jest.useFakeTimers();
68+
const onEdit = jest.fn();
69+
const wrapper = mount(
70+
getTabs({ editable: { onEdit }, moreTabsDropdownProps: { trigger: 'click' } }),
71+
);
72+
73+
triggerResize(wrapper);
74+
act(() => {
75+
jest.runAllTimers();
76+
wrapper.update();
77+
});
78+
79+
// hover
80+
wrapper.find('.rc-tabs-nav-more').simulate('mouseenter');
81+
jest.runAllTimers();
82+
wrapper.update();
83+
expect(wrapper.find('.rc-tabs-dropdown')).toHaveLength(0);
84+
85+
// click
86+
wrapper.find('.rc-tabs-nav-more').simulate('click');
87+
expect(wrapper.find('.rc-tabs-dropdown').hasClass('ant-tabs-dropdown-hidden')).toBeFalsy();
88+
89+
wrapper.unmount();
90+
91+
jest.useRealTimers();
92+
});
6593
});

0 commit comments

Comments
 (0)