From 9e74910f974544722b21ecbcf0b57e62c38661b7 Mon Sep 17 00:00:00 2001 From: Jony J <1844749591@qq.com> Date: Wed, 12 Feb 2025 11:48:55 +0800 Subject: [PATCH 01/13] feat: retire deprecated api (#768) --- docs/demo/renderTabBar-use-panes.md | 8 ----- docs/examples/renderTabBar-use-panes.tsx | 43 ------------------------ src/TabNavList/Wrapper.tsx | 15 ++------- src/Tabs.tsx | 1 - src/interface.ts | 2 -- tests/index.test.tsx | 17 ---------- 6 files changed, 2 insertions(+), 84 deletions(-) delete mode 100644 docs/demo/renderTabBar-use-panes.md delete mode 100644 docs/examples/renderTabBar-use-panes.tsx diff --git a/docs/demo/renderTabBar-use-panes.md b/docs/demo/renderTabBar-use-panes.md deleted file mode 100644 index 616e1cfc..00000000 --- a/docs/demo/renderTabBar-use-panes.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: enderTabBar-use-panes -nav: - title: Demo - path: /demo ---- - - diff --git a/docs/examples/renderTabBar-use-panes.tsx b/docs/examples/renderTabBar-use-panes.tsx deleted file mode 100644 index a976effe..00000000 --- a/docs/examples/renderTabBar-use-panes.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import Tabs from '../../src'; -import '../../assets/index.less'; - -const renderTabBar = props => { - return ( -
- {props.panes.map(pane => { - const { key } = pane; - return {key}; - })} -
- ); -}; - -export default () => { - return ( -
- -
- ); -}; diff --git a/src/TabNavList/Wrapper.tsx b/src/TabNavList/Wrapper.tsx index a2b4bd50..b4203554 100644 --- a/src/TabNavList/Wrapper.tsx +++ b/src/TabNavList/Wrapper.tsx @@ -3,25 +3,14 @@ import * as React from 'react'; import type { TabNavListProps } from '.'; import TabNavList from '.'; -import TabContext from '../TabContext'; -import TabPane from '../TabPanelList/TabPane'; - + export type TabNavListWrapperProps = Required> & TabNavListProps; // We have to create a TabNavList components. const TabNavListWrapper: React.FC = ({ renderTabBar, ...restProps }) => { - const { tabs } = React.useContext(TabContext); if (renderTabBar) { - const tabNavBarProps = { - ...restProps, - // Legacy support. We do not use this actually - panes: tabs.map(({ label, key, ...restTabProps }) => ( - - )), - }; - - return renderTabBar(tabNavBarProps, TabNavList); + return renderTabBar(restProps, TabNavList); } return ; diff --git a/src/Tabs.tsx b/src/Tabs.tsx index 7d6df768..6a288859 100644 --- a/src/Tabs.tsx +++ b/src/Tabs.tsx @@ -178,7 +178,6 @@ const Tabs = React.forwardRef((props, ref) => { onTabScroll, extra: tabBarExtraContent, style: tabBarStyle, - panes: null, getPopupContainer, popupClassName, indicator, diff --git a/src/interface.ts b/src/interface.ts index ea7958af..162e1345 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -51,8 +51,6 @@ type RenderTabBarProps = { onTabScroll: OnTabScroll; extra: TabBarExtraContent; style: React.CSSProperties; - /** @deprecated It do not pass real TabPane node. Only for compatible usage. */ - panes: React.ReactNode; }; export type RenderTabBar = ( diff --git a/tests/index.test.tsx b/tests/index.test.tsx index db5bc7d9..a7488dd9 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -310,23 +310,6 @@ describe('Tabs.Basic', () => { expect(container.querySelector('.my-node')).toBeTruthy(); expect(renderTabBar).toHaveBeenCalled(); }); - it('has panes property in props', () => { - const renderTabBar = props => { - return ( -
- {props.panes.map(pane => ( - - tab - - ))} -
- ); - }; - const { container } = render(getTabs({ renderTabBar })); - expect(container.querySelector('[data-key="light"]')).toBeTruthy(); - expect(container.querySelector('[data-key="bamboo"]')).toBeTruthy(); - expect(container.querySelector('[data-key="cute"]')).toBeTruthy(); - }); }); it('destroyInactiveTabPane', () => { From 1559c3b5f8149f2bf4b8b435b7b7441270ec4fd1 Mon Sep 17 00:00:00 2001 From: Jony J <1844749591@qq.com> Date: Wed, 12 Feb 2025 17:27:58 +0800 Subject: [PATCH 02/13] chore: migrate to @rc-component namespace (#779) * chore: migrate to @rc-component namespace * chore: adjust script * chore: adjust script --- .fatherrc.js => .fatherrc.ts | 0 package.json | 18 +++++++++--------- tsconfig.json | 3 +++ 3 files changed, 12 insertions(+), 9 deletions(-) rename .fatherrc.js => .fatherrc.ts (100%) diff --git a/.fatherrc.js b/.fatherrc.ts similarity index 100% rename from .fatherrc.js rename to .fatherrc.ts diff --git a/package.json b/package.json index 8816f77c..298a9012 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "rc-tabs", - "version": "15.5.1", + "name": "@rc-component/tabs", + "version": "1.0.0", "description": "tabs ui component for react", "keywords": [ "react", @@ -32,21 +32,22 @@ "docs:deploy": "gh-pages -d .doc", "lint": "eslint src/ docs/examples/ --ext .tsx,.ts,.jsx,.js", "now-build": "npm run build", - "prepublishOnly": "npm run lint && npm run test && npm run compile && np --yolo --no-publish", + "prepublishOnly": "npm run lint && npm run test && npm run compile && rc-np", "start": "dumi dev", "test": "rc-test" }, "dependencies": { - "@babel/runtime": "^7.11.2", + "@rc-component/resize-observer": "^1.0.0", + "@rc-component/util": "^1.2.0", + "@rc-component/motion": "^1.1.3", "classnames": "2.x", "rc-dropdown": "~4.2.0", "rc-menu": "~9.16.0", - "rc-motion": "^2.6.2", - "rc-resize-observer": "^1.0.0", - "rc-util": "^5.34.1" + "rc-motion": "^2.6.2" }, "devDependencies": { - "@rc-component/father-plugin": "^1.0.0", + "@rc-component/father-plugin": "^2.0.0", + "@rc-component/np": "^1.0.3", "@rc-component/trigger": "^2.0.0", "@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "^16.0.1", @@ -70,7 +71,6 @@ "history": "^5.3.0", "immutability-helper": "^3.0.1", "less": "^4.1.3", - "np": "^10.0.2", "preact-compat": "^3.16.0", "rc-test": "^7.0.14", "react": "^18.0.0", diff --git a/tsconfig.json b/tsconfig.json index aeeacaa4..7a55add9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,6 +20,9 @@ ], "rc-tabs": [ "src/" + ], + "@rc-component/tabs": [ + "src/" ] } }, From 6d02218f91f4d4f84a4aaf89c70e56cacb07f02a Mon Sep 17 00:00:00 2001 From: Jony J <1844749591@qq.com> Date: Mon, 17 Feb 2025 16:03:54 +0800 Subject: [PATCH 03/13] fix: improve TabPane accessibility and content handling (#780) * fix: improve TabPane accessibility and content handling * test: prevent focus on empty tab panel --- src/TabPanelList/TabPane.tsx | 4 +++- tests/accessibility.test.tsx | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/TabPanelList/TabPane.tsx b/src/TabPanelList/TabPane.tsx index 510520d7..d1b803d3 100644 --- a/src/TabPanelList/TabPane.tsx +++ b/src/TabPanelList/TabPane.tsx @@ -23,11 +23,13 @@ export interface TabPaneProps { const TabPane = React.forwardRef((props, ref) => { const { prefixCls, className, style, id, active, tabKey, children } = props; + const hasContent = React.Children.count(children) > 0; + return (
{ const firstTab = getByRole('tab', { name: /Tab1/i }); expect(firstTab).toHaveFocus(); }); + + it('should not focus on tab panel when it is empty', async () => { + const user = userEvent.setup(); + const { getByRole } = render( + , + ); + + const tabPanel = getByRole('tabpanel', { name: /Tab1/i }); + await user.tab(); + await user.tab(); + expect(tabPanel).not.toHaveFocus(); + }); }); From ffde754b90a40806f278ffe082c2b9c6fdaa5b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Mon, 17 Feb 2025 16:36:52 +0800 Subject: [PATCH 04/13] chore: bump version to 1.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 298a9012..894829eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rc-component/tabs", - "version": "1.0.0", + "version": "1.1.0", "description": "tabs ui component for react", "keywords": [ "react", From ca9a372dea6e0a214ad711f6e9cf39d670ef5d50 Mon Sep 17 00:00:00 2001 From: thinkasany <480968828@qq.com> Date: Thu, 20 Feb 2025 15:00:29 +0800 Subject: [PATCH 05/13] feat: tab support classnames and styles (#784) * feat: tab support classnames and styles * fix: test * fix * fix * fix --- src/TabNavList/OperationNode.tsx | 7 +++++-- src/TabNavList/TabNode.tsx | 4 +++- src/TabNavList/index.tsx | 13 ++++++++++--- src/Tabs.tsx | 10 +++++++++- tests/index.test.tsx | 25 +++++++++++++++++++++++++ tests/overflow.test.tsx | 16 +++++++++++++--- 6 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/TabNavList/OperationNode.tsx b/src/TabNavList/OperationNode.tsx index 87a44c80..4c29c572 100644 --- a/src/TabNavList/OperationNode.tsx +++ b/src/TabNavList/OperationNode.tsx @@ -26,6 +26,7 @@ export interface OperationNodeProps { tabMoving?: boolean; getPopupContainer?: (node: HTMLElement) => HTMLElement; popupClassName?: string; + popupStyle?: React.CSSProperties; } const OperationNode = React.forwardRef((props, ref) => { @@ -45,6 +46,7 @@ const OperationNode = React.forwardRef((prop onTabClick, getPopupContainer, popupClassName, + popupStyle, } = props; // ======================== Dropdown ======================== const [open, setOpen] = useState(false); @@ -182,7 +184,7 @@ const OperationNode = React.forwardRef((prop moreStyle.order = 1; } - const overlayClassName = classNames({ + const overlayClassName = classNames(popupClassName, { [`${dropdownPrefix}-rtl`]: rtl, }); @@ -192,7 +194,8 @@ const OperationNode = React.forwardRef((prop overlay={menu} visible={tabs.length ? open : false} onVisibleChange={setOpen} - overlayClassName={classNames(overlayClassName, popupClassName)} + overlayClassName={overlayClassName} + overlayStyle={popupStyle} mouseEnterDelay={0.1} mouseLeaveDelay={0.1} getPopupContainer={getPopupContainer} diff --git a/src/TabNavList/TabNode.tsx b/src/TabNavList/TabNode.tsx index d3c0d944..0c1e34fd 100644 --- a/src/TabNavList/TabNode.tsx +++ b/src/TabNavList/TabNode.tsx @@ -24,6 +24,7 @@ export interface TabNodeProps { onFocus: React.FocusEventHandler; onBlur: React.FocusEventHandler; style?: React.CSSProperties; + className?: string; } const TabNode: React.FC = props => { @@ -44,6 +45,7 @@ const TabNode: React.FC = props => { onMouseDown, onMouseUp, style, + className, tabCount, currentPosition, } = props; @@ -81,7 +83,7 @@ const TabNode: React.FC = props => {
>; + styles?: Partial>; } const getTabSize = (tab: HTMLElement, containerRect: { left: number; top: number }) => { @@ -109,6 +112,8 @@ const TabNavList = React.forwardRef((props, ref onTabClick, onTabScroll, indicator, + classNames: tabsClassNames, + styles, } = props; const { prefixCls, tabs } = React.useContext(TabContext); @@ -417,8 +422,9 @@ const TabNavList = React.forwardRef((props, ref prefixCls={prefixCls} key={key} tab={tab} + className={tabsClassNames?.item} /* first node should not have margin left */ - style={i === 0 ? undefined : tabNodeStyle} + style={i === 0 ? styles?.item : { ...tabNodeStyle, ...styles?.item }} closable={tab.closable} editable={editable} active={key === activeKey} @@ -607,10 +613,10 @@ const TabNavList = React.forwardRef((props, ref }} />
@@ -624,6 +630,7 @@ const TabNavList = React.forwardRef((props, ref prefixCls={prefixCls} tabs={hiddenTabs} className={!hasDropdown && operationsHiddenClassName} + popupStyle={styles?.popup} tabMoving={!!lockAnimation} /> diff --git a/src/Tabs.tsx b/src/Tabs.tsx index 6a288859..f6cdb03b 100644 --- a/src/Tabs.tsx +++ b/src/Tabs.tsx @@ -34,11 +34,15 @@ import type { // Used for accessibility let uuid = 0; +export type SemanticName = 'popup' | 'item' | 'indicator'; + export interface TabsProps extends Omit, 'onChange' | 'children'> { prefixCls?: string; className?: string; style?: React.CSSProperties; + classNames?: Partial>; + styles?: Partial>; id?: string; items?: Tab[]; @@ -99,6 +103,8 @@ const Tabs = React.forwardRef((props, ref) => { getPopupContainer, popupClassName, indicator, + classNames: tabsClassNames, + styles, ...restProps } = props; const tabs = React.useMemo( @@ -179,7 +185,9 @@ const Tabs = React.forwardRef((props, ref) => { extra: tabBarExtraContent, style: tabBarStyle, getPopupContainer, - popupClassName, + popupClassName: classNames(popupClassName, tabsClassNames?.popup), + styles, + classNames: tabsClassNames, indicator, }; diff --git a/tests/index.test.tsx b/tests/index.test.tsx index a7488dd9..12185d10 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -689,4 +689,29 @@ describe('Tabs.Basic', () => { expect(parseInt(startBar.style.top)).toBeLessThanOrEqual(parseInt(centerBar.style.top)); expect(parseInt(centerBar.style.top)).toBeLessThanOrEqual(parseInt(endBar.style.top)); }); + it('support classnames and styles', () => { + const customClassNames = { + indicator: 'custom-indicator', + item: 'custom-item', + }; + const customStyles = { + indicator: { background: 'red' }, + item: { color: 'blue' }, + }; + const { container } = render( + , + ); + const indicator = container.querySelector('.rc-tabs-ink-bar') as HTMLElement; + const item = container.querySelector('.rc-tabs-tab') as HTMLElement; + + expect(indicator).toHaveClass('custom-indicator'); + expect(item).toHaveClass('custom-item'); + expect(indicator).toHaveStyle({ background: 'red' }); + expect(item).toHaveStyle({ color: 'blue' }); + }); }); diff --git a/tests/overflow.test.tsx b/tests/overflow.test.tsx index 509bbae6..cc8165e4 100644 --- a/tests/overflow.test.tsx +++ b/tests/overflow.test.tsx @@ -95,12 +95,14 @@ describe('Tabs.Overflow', () => { it('should open dropdown on click when moreTrigger is set to click', () => { jest.useFakeTimers(); const onChange = jest.fn(); - const { container, unmount } = render(getTabs({ onChange, more: {icon: '...', trigger: 'click'} })); + const { container, unmount } = render( + getTabs({ onChange, more: { icon: '...', trigger: 'click' } }), + ); triggerResize(container); act(() => { jest.runAllTimers(); }); - const button = container.querySelector('.rc-tabs-nav-more') + const button = container.querySelector('.rc-tabs-nav-more'); fireEvent.click(button); act(() => { jest.runAllTimers(); @@ -504,7 +506,13 @@ describe('Tabs.Overflow', () => { it('should support popupClassName', () => { jest.useFakeTimers(); - const { container } = render(getTabs({ popupClassName: 'custom-popup' })); + const { container } = render( + getTabs({ + popupClassName: 'custom-popup', + classNames: { popup: 'classnames-popup' }, + styles: { popup: { color: 'red' } }, + }), + ); triggerResize(container); act(() => { @@ -516,6 +524,8 @@ describe('Tabs.Overflow', () => { jest.runAllTimers(); }); expect(document.querySelector('.rc-tabs-dropdown')).toHaveClass('custom-popup'); + expect(document.querySelector('.rc-tabs-dropdown')).toHaveClass('classnames-popup'); + expect(document.querySelector('.rc-tabs-dropdown')).toHaveStyle('color: red'); }); it('correct handle decimal', () => { From 1bc44a5e8d21fc4ea91f3227073472de5c46c94c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Thu, 20 Feb 2025 15:08:18 +0800 Subject: [PATCH 06/13] chore: bump version to 1.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 894829eb..16bd6728 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rc-component/tabs", - "version": "1.1.0", + "version": "1.2.0", "description": "tabs ui component for react", "keywords": [ "react", From 7d5b243799bbd4552e350c28b993b139e857b21a Mon Sep 17 00:00:00 2001 From: thinkasany <480968828@qq.com> Date: Thu, 20 Feb 2025 17:49:45 +0800 Subject: [PATCH 07/13] feat: tab support classnames and styles (#786) * feat: add content for classnames and styles * add header --- src/TabNavList/index.tsx | 4 ++-- src/TabPanelList/index.tsx | 16 +++++++++++++--- src/Tabs.tsx | 6 ++++-- tests/index.test.tsx | 11 +++++++++++ 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/TabNavList/index.tsx b/src/TabNavList/index.tsx index 7411f579..7b49007b 100644 --- a/src/TabNavList/index.tsx +++ b/src/TabNavList/index.tsx @@ -573,8 +573,8 @@ const TabNavList = React.forwardRef((props, ref ref={useComposeRef(ref, containerRef)} role="tablist" aria-orientation={tabPositionTopOrBottom ? 'horizontal' : 'vertical'} - className={classNames(`${prefixCls}-nav`, className)} - style={style} + className={classNames(`${prefixCls}-nav`, className, tabsClassNames?.header)} + style={{ ...styles?.header, ...style }} onKeyDown={() => { // No need animation when use keyboard doLockAnimation(); diff --git a/src/TabPanelList/index.tsx b/src/TabPanelList/index.tsx index 0957bbb6..e340498d 100644 --- a/src/TabPanelList/index.tsx +++ b/src/TabPanelList/index.tsx @@ -11,10 +11,20 @@ export interface TabPanelListProps { animated?: AnimatedConfig; tabPosition?: TabPosition; destroyInactiveTabPane?: boolean; + contentStyle?: React.CSSProperties; + contentClassName?: string; } const TabPanelList: React.FC = props => { - const { id, activeKey, animated, tabPosition, destroyInactiveTabPane } = props; + const { + id, + activeKey, + animated, + tabPosition, + destroyInactiveTabPane, + contentStyle, + contentClassName, + } = props; const { prefixCls, tabs } = React.useContext(TabContext); const tabPaneAnimated = animated.tabPane; @@ -54,8 +64,8 @@ const TabPanelList: React.FC = props => { tabKey={key} animated={tabPaneAnimated} active={active} - style={{ ...paneStyle, ...motionStyle }} - className={classNames(paneClassName, motionClassName)} + style={{ ...contentStyle, ...paneStyle, ...motionStyle }} + className={classNames(contentClassName, paneClassName, motionClassName)} ref={ref} /> )} diff --git a/src/Tabs.tsx b/src/Tabs.tsx index f6cdb03b..144dd3b7 100644 --- a/src/Tabs.tsx +++ b/src/Tabs.tsx @@ -34,7 +34,7 @@ import type { // Used for accessibility let uuid = 0; -export type SemanticName = 'popup' | 'item' | 'indicator'; +export type SemanticName = 'popup' | 'item' | 'indicator' | 'content' | 'header'; export interface TabsProps extends Omit, 'onChange' | 'children'> { @@ -186,9 +186,9 @@ const Tabs = React.forwardRef((props, ref) => { style: tabBarStyle, getPopupContainer, popupClassName: classNames(popupClassName, tabsClassNames?.popup), + indicator, styles, classNames: tabsClassNames, - indicator, }; return ( @@ -212,6 +212,8 @@ const Tabs = React.forwardRef((props, ref) => {
diff --git a/tests/index.test.tsx b/tests/index.test.tsx index 12185d10..81cb8c99 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -693,10 +693,14 @@ describe('Tabs.Basic', () => { const customClassNames = { indicator: 'custom-indicator', item: 'custom-item', + content: 'custom-content', + header: 'custom-header', }; const customStyles = { indicator: { background: 'red' }, item: { color: 'blue' }, + content: { background: 'green' }, + header: { background: 'yellow' }, }; const { container } = render( { ); const indicator = container.querySelector('.rc-tabs-ink-bar') as HTMLElement; const item = container.querySelector('.rc-tabs-tab') as HTMLElement; + const content = container.querySelector('.rc-tabs-tabpane') as HTMLElement; + const header = container.querySelector('.rc-tabs-nav') as HTMLElement; expect(indicator).toHaveClass('custom-indicator'); expect(item).toHaveClass('custom-item'); + expect(content).toHaveClass('custom-content'); + expect(header).toHaveClass('custom-header'); + expect(indicator).toHaveStyle({ background: 'red' }); expect(item).toHaveStyle({ color: 'blue' }); + expect(content).toHaveStyle({ background: 'green' }); + expect(header).toHaveStyle({ background: 'yellow' }); }); }); From f65defc7c423ddb19cf82a4d576db5367281a237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Thu, 20 Feb 2025 19:24:48 +0800 Subject: [PATCH 08/13] chore: bump version to 1.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 16bd6728..09318cd5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rc-component/tabs", - "version": "1.2.0", + "version": "1.2.1", "description": "tabs ui component for react", "keywords": [ "react", From a710e4762801bb63e20e173802c8a59a03d12971 Mon Sep 17 00:00:00 2001 From: Jony J <1844749591@qq.com> Date: Tue, 25 Feb 2025 15:21:59 +0800 Subject: [PATCH 09/13] chore: update package dependencies (#788) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: update package dependencies * chore: bump deps --------- Co-authored-by: 二货机器人 --- docs/examples/animated.tsx | 2 +- package.json | 7 +++---- src/TabNavList/OperationNode.tsx | 4 ++-- src/TabPanelList/index.tsx | 2 +- src/interface.ts | 10 +++++----- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/docs/examples/animated.tsx b/docs/examples/animated.tsx index c28d62fa..f6118acb 100644 --- a/docs/examples/animated.tsx +++ b/docs/examples/animated.tsx @@ -1,6 +1,6 @@ import React from 'react'; import Tabs from '../../src'; -import type { CSSMotionProps } from 'rc-motion'; +import type { CSSMotionProps } from '@rc-component/motion'; import '../../assets/index.less'; import './animated.less'; diff --git a/package.json b/package.json index 09318cd5..37b125b2 100644 --- a/package.json +++ b/package.json @@ -41,14 +41,13 @@ "@rc-component/util": "^1.2.0", "@rc-component/motion": "^1.1.3", "classnames": "2.x", - "rc-dropdown": "~4.2.0", - "rc-menu": "~9.16.0", - "rc-motion": "^2.6.2" + "@rc-component/dropdown": "~1.0.0", + "@rc-component/menu": "~1.0.0" }, "devDependencies": { "@rc-component/father-plugin": "^2.0.0", "@rc-component/np": "^1.0.3", - "@rc-component/trigger": "^2.0.0", + "@rc-component/trigger": "^3.0.0", "@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^14.5.2", diff --git a/src/TabNavList/OperationNode.tsx b/src/TabNavList/OperationNode.tsx index 4c29c572..5b58db4e 100644 --- a/src/TabNavList/OperationNode.tsx +++ b/src/TabNavList/OperationNode.tsx @@ -1,6 +1,6 @@ import classNames from 'classnames'; -import Dropdown from 'rc-dropdown'; -import Menu, { MenuItem } from 'rc-menu'; +import Dropdown from '@rc-component/dropdown'; +import Menu, { MenuItem } from '@rc-component/menu'; import KeyCode from 'rc-util/lib/KeyCode'; import * as React from 'react'; import { useEffect, useState } from 'react'; diff --git a/src/TabPanelList/index.tsx b/src/TabPanelList/index.tsx index e340498d..2082c493 100644 --- a/src/TabPanelList/index.tsx +++ b/src/TabPanelList/index.tsx @@ -1,5 +1,5 @@ import classNames from 'classnames'; -import CSSMotion from 'rc-motion'; +import CSSMotion from '@rc-component/motion'; import * as React from 'react'; import type { AnimatedConfig, TabPosition } from '../interface'; import TabContext from '../TabContext'; diff --git a/src/interface.ts b/src/interface.ts index 162e1345..6c62e24e 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -1,15 +1,15 @@ -import type { CSSMotionProps } from 'rc-motion'; +import type { CSSMotionProps } from '@rc-component/motion'; +import { DropdownProps } from '@rc-component/dropdown/lib/Dropdown'; import type React from 'react'; import type { TabNavListProps } from './TabNavList'; import type { TabPaneProps } from './TabPanelList/TabPane'; -import { DropdownProps } from 'rc-dropdown/lib/Dropdown'; export type TriggerProps = { trigger?: 'hover' | 'click'; -} +}; export type moreIcon = React.ReactNode; export type MoreProps = { - icon?: moreIcon, + icon?: moreIcon; } & Omit; export type SizeInfo = [width: number, height: number]; @@ -45,7 +45,7 @@ type RenderTabBarProps = { mobile: boolean; editable: EditableConfig; locale: TabsLocale; - more: MoreProps, + more: MoreProps; tabBarGutter: number; onTabClick: (key: string, e: React.MouseEvent | React.KeyboardEvent) => void; onTabScroll: OnTabScroll; From 629f13ba97bf0c452b991371a274288ef596bb22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 25 Feb 2025 15:26:49 +0800 Subject: [PATCH 10/13] chore: bump version to 1.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 37b125b2..2802eb42 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rc-component/tabs", - "version": "1.2.1", + "version": "1.3.0", "description": "tabs ui component for react", "keywords": [ "react", From c08b866fb5ad8f6f50b9adb6c47f8008b9655515 Mon Sep 17 00:00:00 2001 From: afc163 Date: Tue, 1 Apr 2025 15:59:47 +0800 Subject: [PATCH 11/13] fix: Tabs press Enter/Space on active tab should not trigger onChange (#790) * fix: Tabs press Enter/Space on active tab should not trigger onChange * fix * fix lint * remove unused devdeps --- .husky/pre-commit | 1 + docs/examples/basic.tsx | 7 ++++++- package.json | 18 ++++++++++-------- src/TabNavList/index.tsx | 3 ++- tests/accessibility.test.tsx | 5 ++++- 5 files changed, 23 insertions(+), 11 deletions(-) create mode 100644 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 00000000..d0a77842 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged \ No newline at end of file diff --git a/docs/examples/basic.tsx b/docs/examples/basic.tsx index b97a0962..7c460422 100644 --- a/docs/examples/basic.tsx +++ b/docs/examples/basic.tsx @@ -38,7 +38,11 @@ export default () => { } const onTabClick = (key: string) => { - console.log('key', key); + console.log('onTabClick', key); + }; + + const onChange = (key: string) => { + console.log('onChange', key); }; return ( @@ -46,6 +50,7 @@ export default () => { diff --git a/package.json b/package.json index 2802eb42..91a8efb5 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "now-build": "npm run build", "prepublishOnly": "npm run lint && npm run test && npm run compile && rc-np", "start": "dumi dev", - "test": "rc-test" + "test": "rc-test", + "prepare": "husky && dumi setup" }, "dependencies": { "@rc-component/resize-observer": "^1.0.0", @@ -45,6 +46,8 @@ "@rc-component/menu": "~1.0.0" }, "devDependencies": { + "@typescript-eslint/eslint-plugin": "^5.59.7", + "@typescript-eslint/parser": "^5.59.7", "@rc-component/father-plugin": "^2.0.0", "@rc-component/np": "^1.0.3", "@rc-component/trigger": "^3.0.0", @@ -54,36 +57,35 @@ "@types/classnames": "^2.2.10", "@types/enzyme": "^3.10.5", "@types/jest": "^29.4.0", - "@types/keyv": "4.2.0", "@types/react": "^18.2.42", "@types/react-dom": "^18.0.11", "@umijs/fabric": "^4.0.1", - "coveralls": "^3.0.6", "cross-env": "^7.0.2", "dumi": "^2.0.0", "eslint": "^8.54.0", "eslint-plugin-jest": "^28.9.0", "eslint-plugin-unicorn": "^56.0.1", - "fastclick": "~1.0.6", "father": "^4.0.0", "gh-pages": "^6.1.0", - "history": "^5.3.0", - "immutability-helper": "^3.0.1", + "husky": "^9.1.7", "less": "^4.1.3", - "preact-compat": "^3.16.0", + "lint-staged": "^15.5.0", + "prettier": "^3.5.3", "rc-test": "^7.0.14", "react": "^18.0.0", "react-dnd": "^10.0.0", "react-dnd-html5-backend": "^10.0.0", "react-dom": "^18.0.0", "react-sticky": "^6.0.3", - "sortablejs": "^1.7.0", "typescript": "^5.3.2" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" }, + "lint-staged": { + "*": "prettier --write --ignore-unknown" + }, "engines": { "node": ">=8.x" } diff --git a/src/TabNavList/index.tsx b/src/TabNavList/index.tsx index 7b49007b..1caca657 100644 --- a/src/TabNavList/index.tsx +++ b/src/TabNavList/index.tsx @@ -375,8 +375,9 @@ const TabNavList = React.forwardRef((props, ref // Enter & Space case 'Enter': case 'Space': { + console.log('press', code); e.preventDefault(); - onTabClick(focusKey, e); + onTabClick(activeKey, e); break; } // Backspace diff --git a/tests/accessibility.test.tsx b/tests/accessibility.test.tsx index bb0531a4..809a2409 100644 --- a/tests/accessibility.test.tsx +++ b/tests/accessibility.test.tsx @@ -91,9 +91,10 @@ describe('Tabs.Accessibility', () => { it('should activate tab on Enter/Space', async () => { const onTabClick = jest.fn(); + const onChange = jest.fn(); const user = userEvent.setup(); - render(createTabs({ onTabClick })); + render(createTabs({ onTabClick, onChange })); // jump to first tab await user.tab(); @@ -101,6 +102,7 @@ describe('Tabs.Accessibility', () => { // activate tab await user.keyboard(' '); expect(onTabClick).toHaveBeenCalledTimes(1); + expect(onChange).not.toHaveBeenCalled(); // move focus to second tab await user.keyboard('{ArrowRight}'); @@ -108,6 +110,7 @@ describe('Tabs.Accessibility', () => { // activate tab await user.keyboard('{Enter}'); expect(onTabClick).toHaveBeenCalledTimes(2); + expect(onChange).not.toHaveBeenCalled(); }); it('should not navigate to disabled tabs', async () => { From 525d42c5b307f873ca56706b647feae9abd42653 Mon Sep 17 00:00:00 2001 From: afc163 Date: Tue, 1 Apr 2025 16:02:48 +0800 Subject: [PATCH 12/13] fix: Tabs press Enter/Space on active tab should not trigger onChange --- docs/examples/basic.tsx | 7 ++++++- package.json | 13 ++++++------- src/TabNavList/index.tsx | 3 ++- tests/accessibility.test.tsx | 5 ++++- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/docs/examples/basic.tsx b/docs/examples/basic.tsx index b97a0962..7c460422 100644 --- a/docs/examples/basic.tsx +++ b/docs/examples/basic.tsx @@ -38,7 +38,11 @@ export default () => { } const onTabClick = (key: string) => { - console.log('key', key); + console.log('onTabClick', key); + }; + + const onChange = (key: string) => { + console.log('onChange', key); }; return ( @@ -46,6 +50,7 @@ export default () => { diff --git a/package.json b/package.json index 8816f77c..9a8b1ef0 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "now-build": "npm run build", "prepublishOnly": "npm run lint && npm run test && npm run compile && np --yolo --no-publish", "start": "dumi dev", - "test": "rc-test" + "test": "rc-test", + "prepare": "husky && dumi setup" }, "dependencies": { "@babel/runtime": "^7.11.2", @@ -54,21 +55,17 @@ "@types/classnames": "^2.2.10", "@types/enzyme": "^3.10.5", "@types/jest": "^29.4.0", - "@types/keyv": "4.2.0", "@types/react": "^18.2.42", "@types/react-dom": "^18.0.11", "@umijs/fabric": "^4.0.1", - "coveralls": "^3.0.6", "cross-env": "^7.0.2", "dumi": "^2.0.0", "eslint": "^8.54.0", "eslint-plugin-jest": "^28.9.0", "eslint-plugin-unicorn": "^56.0.1", - "fastclick": "~1.0.6", "father": "^4.0.0", "gh-pages": "^6.1.0", - "history": "^5.3.0", - "immutability-helper": "^3.0.1", + "husky": "^9.1.7", "less": "^4.1.3", "np": "^10.0.2", "preact-compat": "^3.16.0", @@ -78,13 +75,15 @@ "react-dnd-html5-backend": "^10.0.0", "react-dom": "^18.0.0", "react-sticky": "^6.0.3", - "sortablejs": "^1.7.0", "typescript": "^5.3.2" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" }, + "lint-staged": { + "*": "prettier --write --ignore-unknown" + }, "engines": { "node": ">=8.x" } diff --git a/src/TabNavList/index.tsx b/src/TabNavList/index.tsx index 332974da..8a4f4376 100644 --- a/src/TabNavList/index.tsx +++ b/src/TabNavList/index.tsx @@ -370,8 +370,9 @@ const TabNavList = React.forwardRef((props, ref // Enter & Space case 'Enter': case 'Space': { + console.log('press', code); e.preventDefault(); - onTabClick(focusKey, e); + onTabClick(activeKey, e); break; } // Backspace diff --git a/tests/accessibility.test.tsx b/tests/accessibility.test.tsx index 25081cda..2114320a 100644 --- a/tests/accessibility.test.tsx +++ b/tests/accessibility.test.tsx @@ -91,9 +91,10 @@ describe('Tabs.Accessibility', () => { it('should activate tab on Enter/Space', async () => { const onTabClick = jest.fn(); + const onChange = jest.fn(); const user = userEvent.setup(); - render(createTabs({ onTabClick })); + render(createTabs({ onTabClick, onChange })); // jump to first tab await user.tab(); @@ -101,6 +102,7 @@ describe('Tabs.Accessibility', () => { // activate tab await user.keyboard(' '); expect(onTabClick).toHaveBeenCalledTimes(1); + expect(onChange).not.toHaveBeenCalled(); // move focus to second tab await user.keyboard('{ArrowRight}'); @@ -108,6 +110,7 @@ describe('Tabs.Accessibility', () => { // activate tab await user.keyboard('{Enter}'); expect(onTabClick).toHaveBeenCalledTimes(2); + expect(onChange).not.toHaveBeenCalled(); }); it('should not navigate to disabled tabs', async () => { From acb0cceceb16438619819e867711314e04fe11fb Mon Sep 17 00:00:00 2001 From: afc163 Date: Tue, 1 Apr 2025 16:04:45 +0800 Subject: [PATCH 13/13] Apply suggestions from code review --- package.json | 7 +------ src/TabNavList/index.tsx | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/package.json b/package.json index 9a8b1ef0..e50aacc8 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,7 @@ "now-build": "npm run build", "prepublishOnly": "npm run lint && npm run test && npm run compile && np --yolo --no-publish", "start": "dumi dev", - "test": "rc-test", - "prepare": "husky && dumi setup" + "test": "rc-test" }, "dependencies": { "@babel/runtime": "^7.11.2", @@ -65,7 +64,6 @@ "eslint-plugin-unicorn": "^56.0.1", "father": "^4.0.0", "gh-pages": "^6.1.0", - "husky": "^9.1.7", "less": "^4.1.3", "np": "^10.0.2", "preact-compat": "^3.16.0", @@ -81,9 +79,6 @@ "react": ">=16.9.0", "react-dom": ">=16.9.0" }, - "lint-staged": { - "*": "prettier --write --ignore-unknown" - }, "engines": { "node": ">=8.x" } diff --git a/src/TabNavList/index.tsx b/src/TabNavList/index.tsx index 8a4f4376..6693bd34 100644 --- a/src/TabNavList/index.tsx +++ b/src/TabNavList/index.tsx @@ -370,7 +370,6 @@ const TabNavList = React.forwardRef((props, ref // Enter & Space case 'Enter': case 'Space': { - console.log('press', code); e.preventDefault(); onTabClick(activeKey, e); break;