From b0febf174fe3e5813475c021827ce0d2edd66ed2 Mon Sep 17 00:00:00 2001 From: Zhou Bill <735051883@qq.com> Date: Wed, 6 Sep 2023 18:01:19 +0800 Subject: [PATCH 01/65] =?UTF-8?q?fix:=20=E6=A0=B9=E6=8D=AEactiveKey?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=A2=9D=E5=A4=96=E5=86=85=E5=AE=B9=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E6=9C=80=E5=90=8E=E4=B8=80=E4=B8=AAtab=E7=82=B9?= =?UTF-8?q?=E5=87=BB=E5=A4=B1=E6=95=88=20(#662)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 根据activeKey显示额外内容导致最后一个tab点击失效 * fix: 添加动态extra demo * chore: back of origin resize --------- Co-authored-by: Bill Co-authored-by: 二货机器人 --- docs/demo/dynamic-extra.md | 8 +++++++ docs/examples/dynamic-extra.tsx | 38 +++++++++++++++++++++++++++++++++ src/TabNavList/index.tsx | 26 +++++++++++----------- 3 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 docs/demo/dynamic-extra.md create mode 100644 docs/examples/dynamic-extra.tsx diff --git a/docs/demo/dynamic-extra.md b/docs/demo/dynamic-extra.md new file mode 100644 index 00000000..8fa940ff --- /dev/null +++ b/docs/demo/dynamic-extra.md @@ -0,0 +1,8 @@ +--- +title: dynamic-extra +nav: + title: Demo + path: /demo +--- + + diff --git a/docs/examples/dynamic-extra.tsx b/docs/examples/dynamic-extra.tsx new file mode 100644 index 00000000..3a32c937 --- /dev/null +++ b/docs/examples/dynamic-extra.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import Tabs from '../../src'; +import type { TabsProps } from '../../src'; +import '../../assets/index.less'; + +const items: TabsProps['items'] = []; +for (let i = 0; i < 50; i += 1) { + items.push({ + key: String(i), + label: `Tab ${i}`, + children: `Content of ${i}`, + }); +} +export default () => { + const [key, setKey] = React.useState('0'); + + const extra = React.useMemo(() => { + if (key === '0') { + return ( +
额外内容
+ ) + } + return null + }, [key]) + + return ( +
+ setKey(curKey)} + tabBarExtraContent={extra} + defaultActiveKey="8" + moreIcon="..." + items={items} + /> +
+ ); +}; \ No newline at end of file diff --git a/src/TabNavList/index.tsx b/src/TabNavList/index.tsx index ff0add85..247c01ff 100644 --- a/src/TabNavList/index.tsx +++ b/src/TabNavList/index.tsx @@ -426,16 +426,17 @@ function TabNavList(props: TabNavListProps, ref: React.Ref) { > -
- + +
+
) { style={indicatorStyle} />
-
-
+
+
+ Date: Wed, 6 Sep 2023 18:02:41 +0800 Subject: [PATCH 02/65] 12.12.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f49b151b..a5cc4bc5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-tabs", - "version": "12.12.0", + "version": "12.12.1", "description": "tabs ui component for react", "engines": { "node": ">=8.x" From 72ca369b95757fa4b44081ea918c7e231914ff64 Mon Sep 17 00:00:00 2001 From: Charlie Jonas Date: Mon, 16 Oct 2023 06:01:54 +0300 Subject: [PATCH 03/65] Fix: apply destroyInactiveTabPane from the TabPane (#675) * apply destroyInactiveTabPane from the TabPane * added TabPane `destroyInactiveTabPane` to readme * fixing syntax error * added unit test --- README.md | 1 + src/TabPanelList/index.tsx | 4 +-- tests/index.test.tsx | 69 +++++++++++++++++++++++++++++++------- 3 files changed, 60 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 4789cf40..4440cece 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ React.render( | name | type | default | description | | --- | --- | --- | --- | +| destroyInactiveTabPane | boolean | false | whether destroy inactive TabPane when change tab | | key | string | - | corresponding to activeKey, should be unique | | forceRender | boolean | false | forced render of content in tabs, not lazy render after clicking on tabs | | tab | ReactNode | - | current tab's title corresponding to current tabPane | diff --git a/src/TabPanelList/index.tsx b/src/TabPanelList/index.tsx index 94f730dd..e1171701 100644 --- a/src/TabPanelList/index.tsx +++ b/src/TabPanelList/index.tsx @@ -33,7 +33,7 @@ export default function TabPanelList({ })} > {tabs.map( - ({ key, forceRender, style: paneStyle, className: paneClassName, ...restTabProps }) => { + ({ key, forceRender, style: paneStyle, className: paneClassName, destroyInactiveTabPane: itemDestroyInactiveTabPane, ...restTabProps }) => { const active = key === activeKey; return ( @@ -41,7 +41,7 @@ export default function TabPanelList({ key={key} visible={active} forceRender={forceRender} - removeOnLeave={!!destroyInactiveTabPane} + removeOnLeave={!!(destroyInactiveTabPane || itemDestroyInactiveTabPane)} leavedClassName={`${tabPanePrefixCls}-hidden`} {...animated.tabPaneMotion} > diff --git a/tests/index.test.tsx b/tests/index.test.tsx index c70782d9..dc91c837 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -372,6 +372,42 @@ describe('Tabs.Basic', () => { matchText('Bamboo'); }); + it('destroyInactiveTabPane from TabPane', () => { + const props = { + activeKey: 'light', + + items: [ + { + key: 'light', + children: 'Light', + destroyInactiveTabPane: true, + }, + { + key: 'bamboo', + children: 'Bamboo', + destroyInactiveTabPane: true, + }, + ] as any, + }; + + const { container, rerender } = render(getTabs(props)); + + function matchText(text: string) { + expect(container.querySelectorAll('.rc-tabs-tabpane')).toHaveLength(1); + expect(container.querySelector('.rc-tabs-tabpane-active').textContent).toEqual(text); + } + + matchText('Light'); + + rerender( + getTabs({ + ...props, + activeKey: 'bamboo', + }), + ); + matchText('Bamboo'); + }); + describe('editable', () => { it('no and', () => { const onEdit = jest.fn(); @@ -493,12 +529,21 @@ describe('Tabs.Basic', () => { const removes = container.querySelectorAll('.rc-tabs-tab-remove'); expect(removes.length).toBe(2); - expect(container.querySelector('[data-node-key="light1"]').querySelector('.rc-tabs-tab-remove')).toBeFalsy(); - expect(container.querySelector('[data-node-key="light2"]').querySelector('.rc-tabs-tab-remove')).toBeFalsy(); - expect(container.querySelector('[data-node-key="light3"]').querySelector('.rc-tabs-tab-remove')).toBeTruthy(); - expect(container.querySelector('[data-node-key="light4"]').querySelector('.rc-tabs-tab-remove')).toBeTruthy(); - expect(container.querySelector('[data-node-key="light5"]').querySelector('.rc-tabs-tab-remove')).toBeFalsy(); - + expect( + container.querySelector('[data-node-key="light1"]').querySelector('.rc-tabs-tab-remove'), + ).toBeFalsy(); + expect( + container.querySelector('[data-node-key="light2"]').querySelector('.rc-tabs-tab-remove'), + ).toBeFalsy(); + expect( + container.querySelector('[data-node-key="light3"]').querySelector('.rc-tabs-tab-remove'), + ).toBeTruthy(); + expect( + container.querySelector('[data-node-key="light4"]').querySelector('.rc-tabs-tab-remove'), + ).toBeTruthy(); + expect( + container.querySelector('[data-node-key="light5"]').querySelector('.rc-tabs-tab-remove'), + ).toBeFalsy(); }); }); @@ -577,20 +622,20 @@ describe('Tabs.Basic', () => { }); it('key contains double quote should not crash', () => { - render() + render(); }); it('key could be number', () => { - render() - }) + render(); + }); - it('support indicatorSize', async () => { + it('support indicatorSize', async () => { const { container, rerender } = render(getTabs({ indicatorSize: 10 })); await waitFakeTimer(); expect(container.querySelector('.rc-tabs-ink-bar')).toHaveStyle({ width: '10px' }); - rerender(getTabs({ indicatorSize: (origin) => origin - 2 })); + rerender(getTabs({ indicatorSize: origin => origin - 2 })); await waitFakeTimer(); expect(container.querySelector('.rc-tabs-ink-bar')).toHaveStyle({ width: '18px' }); - }) + }); }); From ad50b0a42e07a746f59017957b265db181b723bd 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, 16 Oct 2023 11:06:38 +0800 Subject: [PATCH 04/65] 12.13.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a5cc4bc5..28849f09 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-tabs", - "version": "12.12.1", + "version": "12.13.0", "description": "tabs ui component for react", "engines": { "node": ">=8.x" From da3d43c7a0aa0c7396d2ce196a5c4dfa7c20ea96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E7=88=B1=E5=90=83=E7=99=BD=E8=90=9D?= =?UTF-8?q?=E5=8D=9C?= Date: Mon, 16 Oct 2023 20:27:02 +0800 Subject: [PATCH 05/65] fix: Offset logic with decimal (#676) * fix: blink of decimal * test: add test case * chore: all width --- src/TabNavList/index.tsx | 95 ++++++++++++++++++++++++++-------------- tests/common/util.tsx | 14 ++++-- tests/overflow.test.tsx | 75 ++++++++++++++++++++++++++++++- 3 files changed, 147 insertions(+), 37 deletions(-) diff --git a/src/TabNavList/index.tsx b/src/TabNavList/index.tsx index 247c01ff..19284730 100644 --- a/src/TabNavList/index.tsx +++ b/src/TabNavList/index.tsx @@ -4,6 +4,8 @@ import useEvent from 'rc-util/lib/hooks/useEvent'; import { useComposeRef } from 'rc-util/lib/ref'; import * as React from 'react'; import { useEffect, useRef, useState } from 'react'; +import type { GetIndicatorSize } from '../hooks/useIndicator'; +import useIndicator from '../hooks/useIndicator'; import useOffsets from '../hooks/useOffsets'; import useSyncState from '../hooks/useSyncState'; import useTouchMove from '../hooks/useTouchMove'; @@ -26,8 +28,6 @@ import AddButton from './AddButton'; import ExtraContent from './ExtraContent'; import OperationNode from './OperationNode'; import TabNode from './TabNode'; -import useIndicator from '../hooks/useIndicator'; -import type { GetIndicatorSize } from '../hooks/useIndicator'; export interface TabNavListProps { id: string; @@ -53,8 +53,31 @@ export interface TabNavListProps { indicatorSize?: GetIndicatorSize; } +const getTabSize = (tab: HTMLElement, containerRect: { x: number; y: number }) => { + // tabListRef + const { offsetWidth, offsetHeight, offsetTop, offsetLeft } = tab; + const { width, height, x, y } = tab.getBoundingClientRect(); + + // Use getBoundingClientRect to avoid decimal inaccuracy + if (Math.abs(width - offsetWidth) < 1) { + return [width, height, x - containerRect.x, y - containerRect.y]; + } + + return [offsetWidth, offsetHeight, offsetLeft, offsetTop]; +}; + const getSize = (refObj: React.RefObject): SizeInfo => { const { offsetWidth = 0, offsetHeight = 0 } = refObj.current || {}; + + // Use getBoundingClientRect to avoid decimal inaccuracy + if (refObj.current) { + const { width, height } = refObj.current.getBoundingClientRect(); + + if (Math.abs(width - offsetWidth) < 1) { + return [width, height]; + } + } + return [offsetWidth, offsetHeight]; }; @@ -313,14 +336,20 @@ function TabNavList(props: TabNavListProps, ref: React.Ref) { const updateTabSizes = () => setTabSizes(() => { const newSizes: TabSizeMap = new Map(); + const listRect = tabListRef.current?.getBoundingClientRect(); + tabs.forEach(({ key }) => { - const btnNode = tabListRef.current?.querySelector(`[data-node-key="${genDataNodeKey(key)}"]`); + const btnNode = tabListRef.current?.querySelector( + `[data-node-key="${genDataNodeKey(key)}"]`, + ); if (btnNode) { + const [width, height, left, top] = getTabSize(btnNode, listRect); + newSizes.set(key, { - width: btnNode.offsetWidth, - height: btnNode.offsetHeight, - left: btnNode.offsetLeft, - top: btnNode.offsetTop, + width, + height, + left, + top, }); } }); @@ -370,7 +399,7 @@ function TabNavList(props: TabNavListProps, ref: React.Ref) { horizontal: tabPositionTopOrBottom, rtl, indicatorSize, - }) + }); // ========================= Effect ======================== useEffect(() => { @@ -437,33 +466,33 @@ function TabNavList(props: TabNavListProps, ref: React.Ref) { ref={tabsWrapperRef} > -
- {tabNodes} - - -
-
+ > + {tabNodes} + + +
+
diff --git a/tests/common/util.tsx b/tests/common/util.tsx index 02ae5f61..b19cd35d 100644 --- a/tests/common/util.tsx +++ b/tests/common/util.tsx @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-invalid-this */ import { act } from '@testing-library/react'; -import type { ReactWrapper } from 'enzyme'; import { _rs as onEsResize } from 'rc-resize-observer/es/utils/observerUtil'; import { _rs as onLibResize } from 'rc-resize-observer/lib/utils/observerUtil'; import React from 'react'; @@ -17,6 +16,7 @@ import type { TabsProps } from '../../src/Tabs'; export interface HackInfo { container?: number; tabNode?: number; + tabNodeList?: number; add?: number; more?: number; extra?: number; @@ -25,7 +25,15 @@ export interface HackInfo { export function getOffsetSizeFunc(info: HackInfo = {}) { return function getOffsetSize() { - const { container = 50, extra = 10, tabNode = 20, add = 10, more = 10, dropdown = 10 } = info; + const { + container = 50, + extra = 10, + tabNodeList, + tabNode = 20, + add = 10, + more = 10, + dropdown = 10, + } = info; if (this.classList.contains('rc-tabs-nav')) { return container; @@ -36,7 +44,7 @@ export function getOffsetSizeFunc(info: HackInfo = {}) { } if (this.classList.contains('rc-tabs-nav-list')) { - return this.querySelectorAll('.rc-tabs-tab').length * tabNode + add; + return tabNodeList || this.querySelectorAll('.rc-tabs-tab').length * tabNode + add; } if (this.classList.contains('rc-tabs-tab')) { diff --git a/tests/overflow.test.tsx b/tests/overflow.test.tsx index 718e4ae6..eba7dccb 100644 --- a/tests/overflow.test.tsx +++ b/tests/overflow.test.tsx @@ -11,7 +11,7 @@ import { getTabs, getTransformX, getTransformY, - triggerResize, waitFakeTimer, + triggerResize, } from './common/util'; describe('Tabs.Overflow', () => { @@ -19,7 +19,13 @@ describe('Tabs.Overflow', () => { const hackOffsetInfo: HackInfo = {}; + let mockGetBoundingClientRect: ( + ele: HTMLElement, + ) => { x: number; y: number; width: number; height: number } | void = null; + beforeEach(() => { + mockGetBoundingClientRect = null; + Object.keys(hackOffsetInfo).forEach(key => { delete hackOffsetInfo[key]; }); @@ -40,6 +46,16 @@ describe('Tabs.Overflow', () => { offsetTop: { get: btnOffsetPosition, }, + getBoundingClientRect() { + return ( + mockGetBoundingClientRect?.(this) || { + x: 0, + y: 0, + width: 0, + height: 0, + } + ); + }, }); }); @@ -483,4 +499,61 @@ describe('Tabs.Overflow', () => { }); expect(document.querySelector('.rc-tabs-dropdown')).toHaveClass('custom-popup'); }); + + it('correct handle decimal', () => { + hackOffsetInfo.container = 29; + hackOffsetInfo.tabNodeList = 29; + hackOffsetInfo.tabNode = 15; + + mockGetBoundingClientRect = ele => { + if (ele.classList.contains('rc-tabs-tab')) { + const sharedRect = { + x: 0, + y: 0, + width: 14.5, + height: 14.5, + }; + + return ele.getAttribute('data-node-key') === 'bamboo' + ? { + ...sharedRect, + } + : { + ...sharedRect, + x: 14.5, + }; + } + // console.log('ele!!!', ele.className); + }; + + jest.useFakeTimers(); + const { container } = render( + getTabs({ + defaultActiveKey: 'little', + items: [ + { + label: 'bamboo', + key: 'bamboo', + children: 'Bamboo', + }, + { + label: 'little', + key: 'little', + children: 'Little', + }, + ], + }), + ); + + act(() => { + jest.runAllTimers(); + }); + + expect(container.querySelector('.rc-tabs-nav-operations-hidden')).toBeTruthy(); + expect(container.querySelector('.rc-tabs-ink-bar')).toHaveStyle({ + left: '21.75px', + }); + + jest.useRealTimers(); + }); }); From b919db3844f10712fbdcc9a2e2fd38159b8e2068 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, 16 Oct 2023 20:35:29 +0800 Subject: [PATCH 06/65] 12.13.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 28849f09..dbbe9af5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-tabs", - "version": "12.13.0", + "version": "12.13.1", "description": "tabs ui component for react", "engines": { "node": ">=8.x" From 1c40c75f0f763787296bf8053bda898967c0a6f2 Mon Sep 17 00:00:00 2001 From: Varun Dhand <110025628+varundhand@users.noreply.github.com> Date: Sat, 25 Nov 2023 20:15:34 +0530 Subject: [PATCH 07/65] fix: typo in README.md (#678) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4440cece..0ae1b9c6 100644 --- a/README.md +++ b/README.md @@ -124,9 +124,9 @@ rc-tabs is released under the MIT license. ## FAQ -### Resposive Tabs +### Responsive Tabs -There are 3 cases when handling resposive tabs: +There are 3 cases when handling responsive tabs: ![image](https://user-images.githubusercontent.com/27722486/156315099-7e6eda9d-ab77-4b16-9b49-1727c5ec8b26.png) We get hidden tabs through [useVisibleRange.ts](/~https://github.com/react-component/tabs/blob/master/src/hooks/useVisibleRange.ts). From d7f03f325ee0fc6fa737c582442e57a445ddcef6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 25 Nov 2023 22:46:16 +0800 Subject: [PATCH 08/65] chore(deps-dev): bump @types/react-dom from 16.9.18 to 18.0.11 (#648) Bumps [@types/react-dom](/~https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) from 16.9.18 to 18.0.11. - [Release notes](/~https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](/~https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom) --- updated-dependencies: - dependency-name: "@types/react-dom" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dbbe9af5..93289a8d 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@types/jest": "^25.2.3", "@types/keyv": "3.1.4", "@types/react": "^17.0.14", - "@types/react-dom": "^16.9.8", + "@types/react-dom": "^18.0.11", "@umijs/fabric": "^2.3.1", "coveralls": "^3.0.6", "cross-env": "^7.0.2", From 97cc119abc228e3501f2118484da9c817edda0aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 25 Nov 2023 22:49:43 +0800 Subject: [PATCH 09/65] chore(deps-dev): bump @types/jest from 25.2.3 to 29.4.0 (#644) Bumps [@types/jest](/~https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 25.2.3 to 29.4.0. - [Release notes](/~https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](/~https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest) --- updated-dependencies: - dependency-name: "@types/jest" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 93289a8d..1d1e0816 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@testing-library/react": "^13.0.0", "@types/classnames": "^2.2.10", "@types/enzyme": "^3.10.5", - "@types/jest": "^25.2.3", + "@types/jest": "^29.4.0", "@types/keyv": "3.1.4", "@types/react": "^17.0.14", "@types/react-dom": "^18.0.11", From 7f81e6c87b390bafc4e8c5e895b5074ba05167df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 25 Nov 2023 22:55:47 +0800 Subject: [PATCH 10/65] chore(deps-dev): bump @types/keyv from 3.1.4 to 4.2.0 (#629) Bumps [@types/keyv](/~https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/keyv) from 3.1.4 to 4.2.0. - [Release notes](/~https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](/~https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/keyv) --- updated-dependencies: - dependency-name: "@types/keyv" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: lijianan <574980606@qq.com> --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1d1e0816..d676d39f 100644 --- a/package.json +++ b/package.json @@ -46,8 +46,9 @@ "@testing-library/react": "^13.0.0", "@types/classnames": "^2.2.10", "@types/enzyme": "^3.10.5", + "@types/jest": "^25.2.3", + "@types/keyv": "4.2.0", "@types/jest": "^29.4.0", - "@types/keyv": "3.1.4", "@types/react": "^17.0.14", "@types/react-dom": "^18.0.11", "@umijs/fabric": "^2.3.1", From 5067862e6b81ac6a267149350e28fa0b64d31b4f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 25 Nov 2023 22:56:21 +0800 Subject: [PATCH 11/65] chore(deps-dev): bump less from 3.13.1 to 4.1.3 (#545) Bumps [less](/~https://github.com/less/less.js) from 3.13.1 to 4.1.3. - [Release notes](/~https://github.com/less/less.js/releases) - [Changelog](/~https://github.com/less/less.js/blob/master/CHANGELOG.md) - [Commits](/~https://github.com/less/less.js/commits) --- updated-dependencies: - dependency-name: less dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d676d39f..b30264ef 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "gh-pages": "^3.1.0", "history": "^1.17.0", "immutability-helper": "^3.0.1", - "less": "^3.11.1", + "less": "^4.1.3", "np": "^7.5.0", "preact-compat": "^3.16.0", "rc-test": "^7.0.14", From aee6de11d40b7b1be87d7a0dab07a2cabce35182 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 25 Nov 2023 22:58:02 +0800 Subject: [PATCH 12/65] chore(deps-dev): bump history from 1.17.0 to 5.3.0 (#478) Bumps [history](/~https://github.com/remix-run/history) from 1.17.0 to 5.3.0. - [Release notes](/~https://github.com/remix-run/history/releases) - [Commits](/~https://github.com/remix-run/history/compare/v1.17.0...v5.3.0) --- updated-dependencies: - dependency-name: history dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b30264ef..6495cb8b 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "fastclick": "~1.0.6", "father": "^4.0.0", "gh-pages": "^3.1.0", - "history": "^1.17.0", + "history": "^5.3.0", "immutability-helper": "^3.0.1", "less": "^4.1.3", "np": "^7.5.0", From e41908955392461b7602baf36a19608db41ea6bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 25 Nov 2023 23:15:20 +0800 Subject: [PATCH 13/65] chore(deps-dev): bump gh-pages from 3.2.3 to 5.0.0 (#642) Bumps [gh-pages](/~https://github.com/tschaub/gh-pages) from 3.2.3 to 5.0.0. - [Release notes](/~https://github.com/tschaub/gh-pages/releases) - [Changelog](/~https://github.com/tschaub/gh-pages/blob/main/changelog.md) - [Commits](/~https://github.com/tschaub/gh-pages/compare/v3.2.3...v5.0.0) --- updated-dependencies: - dependency-name: gh-pages dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: lijianan <574980606@qq.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6495cb8b..c9bf1a25 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "eslint": "^7.0.0", "fastclick": "~1.0.6", "father": "^4.0.0", - "gh-pages": "^3.1.0", + "gh-pages": "^5.0.0", "history": "^5.3.0", "immutability-helper": "^3.0.1", "less": "^4.1.3", From f68f5f49e0a300e1730754fcc06fc544f029a972 Mon Sep 17 00:00:00 2001 From: Cyber Date: Sat, 25 Nov 2023 09:20:08 -0600 Subject: [PATCH 14/65] docs: fix typo (#615) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ae1b9c6..96b2f5f5 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ React.render( | locale | { dropdownAriaLabel: string, removeAriaLabel: string, addAriaLabel: string } | - | Accessibility locale help text | | moreIcon | ReactNode | - | collapse icon | | tabBarGutter | number | 0 | config tab bar gutter | -| tabBarPosition | `'left' | 'right' | 'top' | 'bottom'` | `'top'` | tab nav 's position | +| tabBarPosition | `'left' \| 'right' \| 'top' \| 'bottom'` | `'top'` | tab nav 's position | | tabBarStyle | style | - | tab nav style | | tabBarExtraContent | ReactNode \| `{ left: ReactNode, right: ReactNode }` | - | config extra content | | renderTabBar | (props, TabBarComponent) => ReactElement | - | How to render tab bar | From 0c66625f299589bf0ba1d556e3573f787809bba2 Mon Sep 17 00:00:00 2001 From: lijianan <574980606@qq.com> Date: Mon, 27 Nov 2023 10:32:22 +0800 Subject: [PATCH 15/65] feat: Tab Item support icon prop (#680) * feat: Tab Item support icon prop * fix: add span Tag for icon * test: update snap * Update src/TabNavList/TabNode.tsx Co-authored-by: MadCcc <1075746765@qq.com> * test: update snap --------- Co-authored-by: MadCcc <1075746765@qq.com> --- docs/examples/basic.tsx | 6 +++++- src/TabNavList/TabNode.tsx | 3 ++- src/TabPanelList/TabPane.tsx | 3 ++- tsconfig.json | 8 ++++++-- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/examples/basic.tsx b/docs/examples/basic.tsx index 5864bc88..f38970ee 100644 --- a/docs/examples/basic.tsx +++ b/docs/examples/basic.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import Tabs from'../../src'; import '../../assets/index.less'; +import Tabs from '../../src'; export default () => { const [destroy, setDestroy] = React.useState(false); @@ -9,17 +9,20 @@ export default () => { label: 'Light', key: 'light', children: 'Light!', + icon: 🌞, }, { label: 'Bamboo', key: 'bamboo', children: 'Bamboo!', + icon: 🎋, }, { label: 'Cute', key: 'cute', children: 'Cute!', disabled: true, + icon: 🐼, }, ]); @@ -38,6 +41,7 @@ export default () => { key: 'yo', label: 'Yo', children: 'Yo!', + icon: 👋, }, ]); }} diff --git a/src/TabNavList/TabNode.tsx b/src/TabNavList/TabNode.tsx index a76d57ac..0914ac29 100644 --- a/src/TabNavList/TabNode.tsx +++ b/src/TabNavList/TabNode.tsx @@ -24,7 +24,7 @@ function TabNode({ prefixCls, id, active, - tab: { key, label, disabled, closeIcon }, + tab: { key, label, disabled, closeIcon, icon }, closable, renderWrapper, removeAriaLabel, @@ -87,6 +87,7 @@ function TabNode({ }} onFocus={onFocus} > + {icon && {icon}} {label} diff --git a/src/TabPanelList/TabPane.tsx b/src/TabPanelList/TabPane.tsx index e153623d..fdb4ba60 100644 --- a/src/TabPanelList/TabPane.tsx +++ b/src/TabPanelList/TabPane.tsx @@ -1,5 +1,5 @@ -import * as React from 'react'; import classNames from 'classnames'; +import * as React from 'react'; export interface TabPaneProps { tab?: React.ReactNode; @@ -10,6 +10,7 @@ export interface TabPaneProps { forceRender?: boolean; closable?: boolean; closeIcon?: React.ReactNode; + icon?: React.ReactNode; // Pass by TabPaneList prefixCls?: string; diff --git a/tsconfig.json b/tsconfig.json index f279d1b9..aeeacaa4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,5 +23,9 @@ ] } }, - "include": [".dumi/**/*", ".dumirc.ts", "**/*.ts", "**/*.tsx"] -} + "include": [ + ".dumirc.ts", + "**/*.ts", + "**/*.tsx" + ] +} \ No newline at end of file From aaad1bff5f5493228a4faebdde233fc3d2236cba Mon Sep 17 00:00:00 2001 From: MadCcc <1075746765@qq.com> Date: Mon, 27 Nov 2023 10:34:15 +0800 Subject: [PATCH 16/65] v12.14.0 --- package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index c9bf1a25..dfd06b0c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-tabs", - "version": "12.13.1", + "version": "12.14.0", "description": "tabs ui component for react", "engines": { "node": ">=8.x" @@ -46,9 +46,8 @@ "@testing-library/react": "^13.0.0", "@types/classnames": "^2.2.10", "@types/enzyme": "^3.10.5", - "@types/jest": "^25.2.3", - "@types/keyv": "4.2.0", "@types/jest": "^29.4.0", + "@types/keyv": "4.2.0", "@types/react": "^17.0.14", "@types/react-dom": "^18.0.11", "@umijs/fabric": "^2.3.1", From fa8ea5f589e4838503577268922b937414b5c2ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 23:56:54 +0800 Subject: [PATCH 17/65] chore(deps-dev): bump eslint from 7.32.0 to 8.35.0 (#652) * chore(deps-dev): bump eslint from 7.32.0 to 8.35.0 Bumps [eslint](/~https://github.com/eslint/eslint) from 7.32.0 to 8.35.0. - [Release notes](/~https://github.com/eslint/eslint/releases) - [Changelog](/~https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](/~https://github.com/eslint/eslint/compare/v7.32.0...v8.35.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Update package.json --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: lijianan <574980606@qq.com> --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index dfd06b0c..d66bf1f1 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,9 @@ "coveralls": "^3.0.6", "cross-env": "^7.0.2", "dumi": "^2.0.0", - "eslint": "^7.0.0", + "eslint": "^8.54.0", + "eslint-plugin-jest": "^27.6.0", + "eslint-plugin-unicorn": "^49.0.0", "fastclick": "~1.0.6", "father": "^4.0.0", "gh-pages": "^5.0.0", From 4c9f6fed95a3cbcfd5cd5b874d8076cb6c0824f1 Mon Sep 17 00:00:00 2001 From: lijianan <574980606@qq.com> Date: Tue, 28 Nov 2023 05:06:03 +0800 Subject: [PATCH 18/65] style: code optimization (#682) --- package.json | 58 ++++++++++----------- src/TabNavList/AddButton.tsx | 14 ++--- src/TabNavList/ExtraContent.tsx | 61 +++++++++++----------- src/TabNavList/OperationNode.tsx | 27 +++++----- src/TabNavList/TabNode.tsx | 34 ++++++------- src/TabNavList/Wrapper.tsx | 11 ++-- src/TabNavList/index.tsx | 43 +++++++--------- src/TabPanelList/TabPane.tsx | 35 +++++++------ src/TabPanelList/index.tsx | 87 +++++++++++++++----------------- src/Tabs.tsx | 27 +++++----- src/hooks/useIndicator.ts | 21 +++----- src/hooks/useOffsets.ts | 2 +- src/hooks/useTouchMove.ts | 2 +- src/index.ts | 2 +- src/interface.ts | 2 +- src/util.ts | 1 + 16 files changed, 204 insertions(+), 223 deletions(-) diff --git a/package.json b/package.json index d66bf1f1..c3f0be24 100644 --- a/package.json +++ b/package.json @@ -2,42 +2,48 @@ "name": "rc-tabs", "version": "12.14.0", "description": "tabs ui component for react", - "engines": { - "node": ">=8.x" - }, "keywords": [ "react", "react-component", "react-tabs" ], - "files": [ - "lib", - "es", - "assets/index.css" - ], - "main": "./lib/index", - "module": "./es/index", "homepage": "http://github.com/react-component/tabs", - "author": "yiminghe@gmail.com", + "bugs": { + "url": "http://github.com/react-component/tabs/issues" + }, "repository": { "type": "git", "url": "git@github.com:react-component/tabs.git" }, - "bugs": { - "url": "http://github.com/react-component/tabs/issues" - }, "license": "MIT", + "author": "yiminghe@gmail.com", + "main": "./lib/index", + "module": "./es/index", + "files": [ + "lib", + "es", + "assets/index.css" + ], "scripts": { - "start": "dumi dev", "build": "dumi build", - "docs:deploy": "gh-pages -d .doc", "compile": "father build && npm run compile:style", - "test": "rc-test", + "compile:style": "lessc --js assets/index.less assets/index.css", "coverage": "father test --coverage", - "now-build": "npm run build", + "docs:deploy": "gh-pages -d .doc", "lint": "eslint src/ docs/examples/ --ext .tsx,.ts,.jsx,.js", - "compile:style": "lessc --js assets/index.less assets/index.css", - "prepublishOnly": "npm run lint && npm run test && npm run compile && np --yolo --no-publish" + "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" + }, + "dependencies": { + "@babel/runtime": "^7.11.2", + "classnames": "2.x", + "rc-dropdown": "~4.1.0", + "rc-menu": "~9.12.0", + "rc-motion": "^2.6.2", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.34.1" }, "devDependencies": { "@rc-component/father-plugin": "^1.0.0", @@ -74,17 +80,11 @@ "sortablejs": "^1.7.0", "typescript": "^4.0.5" }, - "dependencies": { - "@babel/runtime": "^7.11.2", - "classnames": "2.x", - "rc-dropdown": "~4.1.0", - "rc-menu": "~9.12.0", - "rc-motion": "^2.6.2", - "rc-resize-observer": "^1.0.0", - "rc-util": "^5.34.1" - }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" + }, + "engines": { + "node": ">=8.x" } } diff --git a/src/TabNavList/AddButton.tsx b/src/TabNavList/AddButton.tsx index 97040d2a..6b6712f9 100644 --- a/src/TabNavList/AddButton.tsx +++ b/src/TabNavList/AddButton.tsx @@ -8,10 +8,8 @@ export interface AddButtonProps { style?: React.CSSProperties; } -function AddButton( - { prefixCls, editable, locale, style }: AddButtonProps, - ref: React.Ref, -) { +const AddButton = React.forwardRef((props, ref) => { + const { prefixCls, editable, locale, style } = props; if (!editable || editable.showAdd === false) { return null; } @@ -24,14 +22,12 @@ function AddButton( style={style} aria-label={locale?.addAriaLabel || 'Add tab'} onClick={event => { - editable.onEdit('add', { - event, - }); + editable.onEdit('add', { event }); }} > {editable.addIcon || '+'} ); -} +}); -export default React.forwardRef(AddButton); +export default AddButton; diff --git a/src/TabNavList/ExtraContent.tsx b/src/TabNavList/ExtraContent.tsx index 9bbea6f9..0da8cadf 100644 --- a/src/TabNavList/ExtraContent.tsx +++ b/src/TabNavList/ExtraContent.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import type { TabBarExtraPosition, TabBarExtraContent, TabBarExtraMap } from '../interface'; +import type { TabBarExtraContent, TabBarExtraMap, TabBarExtraPosition } from '../interface'; interface ExtraContentProps { position: TabBarExtraPosition; @@ -7,35 +7,36 @@ interface ExtraContentProps { extra?: TabBarExtraContent; } -const ExtraContent = React.forwardRef( - ({ position, prefixCls, extra }, ref) => { - if (!extra) return null; - - let content: React.ReactNode; - - // Parse extra - let assertExtra: TabBarExtraMap = {}; - if (typeof extra === 'object' && !React.isValidElement(extra)) { - assertExtra = extra as TabBarExtraMap; - } else { - assertExtra.right = extra; - } - - if (position === 'right') { - content = assertExtra.right; - } - - if (position === 'left') { - content = assertExtra.left; - } - - return content ? ( -
- {content} -
- ) : null; - }, -); +const ExtraContent = React.forwardRef((props, ref) => { + const { position, prefixCls, extra } = props; + if (!extra) { + return null; + } + + let content: React.ReactNode; + + // Parse extra + let assertExtra: TabBarExtraMap = {}; + if (typeof extra === 'object' && !React.isValidElement(extra)) { + assertExtra = extra as TabBarExtraMap; + } else { + assertExtra.right = extra; + } + + if (position === 'right') { + content = assertExtra.right; + } + + if (position === 'left') { + content = assertExtra.left; + } + + return content ? ( +
+ {content} +
+ ) : null; +}); if (process.env.NODE_ENV !== 'production') { ExtraContent.displayName = 'ExtraContent'; diff --git a/src/TabNavList/OperationNode.tsx b/src/TabNavList/OperationNode.tsx index 19573b4d..bb71adf6 100644 --- a/src/TabNavList/OperationNode.tsx +++ b/src/TabNavList/OperationNode.tsx @@ -5,8 +5,8 @@ import KeyCode from 'rc-util/lib/KeyCode'; import * as React from 'react'; import { useEffect, useState } from 'react'; import type { EditableConfig, Tab, TabsLocale } from '../interface'; -import AddButton from './AddButton'; import { getRemovable } from '../util'; +import AddButton from './AddButton'; export interface OperationNodeProps { prefixCls: string; @@ -29,8 +29,8 @@ export interface OperationNodeProps { popupClassName?: string; } -function OperationNode( - { +const OperationNode = React.forwardRef((props, ref) => { + const { prefixCls, id, tabs, @@ -47,9 +47,7 @@ function OperationNode( onTabClick, getPopupContainer, popupClassName, - }: OperationNodeProps, - ref: React.Ref, -) { + } = props; // ======================== Dropdown ======================== const [open, setOpen] = useState(false); const [selectedKey, setSelectedKey] = useState(null); @@ -63,10 +61,7 @@ function OperationNode( function onRemoveTab(event: React.MouseEvent | React.KeyboardEvent, key: string) { event.preventDefault(); event.stopPropagation(); - editable.onEdit('remove', { - key, - event, - }); + editable.onEdit('remove', { key, event }); } const menu = ( @@ -83,7 +78,7 @@ function OperationNode( selectedKeys={[selectedKey]} aria-label={dropdownAriaLabel !== undefined ? dropdownAriaLabel : 'expanded dropdown'} > - {tabs.map(tab => { + {tabs.map(tab => { const { closable, disabled, closeIcon, key, label } = tab; const removable = getRemovable(closable, closeIcon, editable, disabled); return ( @@ -156,7 +151,9 @@ function OperationNode( break; case KeyCode.SPACE: case KeyCode.ENTER: - if (selectedKey !== null) onTabClick(selectedKey, e); + if (selectedKey !== null) { + onTabClick(selectedKey, e); + } break; } } @@ -189,7 +186,7 @@ function OperationNode( [`${dropdownPrefix}-rtl`]: rtl, }); - const moreNode: React.ReactElement = mobile ? null : ( + const moreNode: React.ReactNode = mobile ? null : ( ); -} +}); export default React.memo( - React.forwardRef(OperationNode), + OperationNode, (_, next) => // /~https://github.com/ant-design/ant-design/issues/32544 // We'd better remove syntactic sugar in `rc-menu` since this has perf issue diff --git a/src/TabNavList/TabNode.tsx b/src/TabNavList/TabNode.tsx index 0914ac29..17de2179 100644 --- a/src/TabNavList/TabNode.tsx +++ b/src/TabNavList/TabNode.tsx @@ -20,19 +20,20 @@ export interface TabNodeProps { style?: React.CSSProperties; } -function TabNode({ - prefixCls, - id, - active, - tab: { key, label, disabled, closeIcon, icon }, - closable, - renderWrapper, - removeAriaLabel, - editable, - onClick, - onFocus, - style, -}: TabNodeProps) { +const TabNode: React.FC = props => { + const { + prefixCls, + id, + active, + tab: { key, label, disabled, closeIcon, icon }, + closable, + renderWrapper, + removeAriaLabel, + editable, + onClick, + onFocus, + style, + } = props; const tabPrefix = `${prefixCls}-tab`; const removable = getRemovable(closable, closeIcon, editable, disabled); @@ -47,10 +48,7 @@ function TabNode({ function onRemoveTab(event: React.MouseEvent | React.KeyboardEvent) { event.preventDefault(); event.stopPropagation(); - editable.onEdit('remove', { - key, - event, - }); + editable.onEdit('remove', { key, event }); } const node: React.ReactElement = ( @@ -110,6 +108,6 @@ function TabNode({ ); return renderWrapper ? renderWrapper(node) : node; -} +}; export default TabNode; diff --git a/src/TabNavList/Wrapper.tsx b/src/TabNavList/Wrapper.tsx index 9b4c034e..63d0ee8a 100644 --- a/src/TabNavList/Wrapper.tsx +++ b/src/TabNavList/Wrapper.tsx @@ -10,15 +10,14 @@ export type TabNavListWrapperProps = Required = ({ 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 }) => ( + panes: tabs.map(({ label, key, ...restTabProps }) => ( )), }; @@ -27,4 +26,10 @@ export default function TabNavListWrapper({ renderTabBar, ...restProps }: TabNav } return ; +}; + +if (process.env.NODE_ENV !== 'production') { + TabNavListWrapper.displayName = 'TabNavListWrapper'; } + +export default TabNavListWrapper; diff --git a/src/TabNavList/index.tsx b/src/TabNavList/index.tsx index 19284730..cae9a3d1 100644 --- a/src/TabNavList/index.tsx +++ b/src/TabNavList/index.tsx @@ -88,8 +88,7 @@ const getUnitValue = (size: SizeInfo, tabPositionTopOrBottom: boolean) => { return size[tabPositionTopOrBottom ? 0 : 1]; }; -function TabNavList(props: TabNavListProps, ref: React.Ref) { - const { prefixCls, tabs } = React.useContext(TabContext); +const TabNavList = React.forwardRef((props, ref) => { const { className, style, @@ -107,14 +106,14 @@ function TabNavList(props: TabNavListProps, ref: React.Ref) { onTabScroll, indicatorSize, } = props; - const containerRef = useRef(); - const extraLeftRef = useRef(); - const extraRightRef = useRef(); - const tabsWrapperRef = useRef(); - const tabListRef = useRef(); - const operationsRef = useRef(); - const innerAddButtonRef = useRef(); - // const [getBtnRef, removeBtnRef] = useRefs(); + const { prefixCls, tabs } = React.useContext(TabContext); + const containerRef = useRef(null); + const extraLeftRef = useRef(null); + const extraRightRef = useRef(null); + const tabsWrapperRef = useRef(null); + const tabListRef = useRef(null); + const operationsRef = useRef(null); + const innerAddButtonRef = useRef(null); const tabPositionTopOrBottom = tabPosition === 'top' || tabPosition === 'bottom'; @@ -179,7 +178,8 @@ function TabNavList(props: TabNavListProps, ref: React.Ref) { } // ========================= Mobile ======================== - const touchMovingRef = useRef(); + const touchMovingRef = useRef>(null); + const [lockAnimation, setLockAnimation] = useState(); function doLockAnimation() { @@ -187,14 +187,15 @@ function TabNavList(props: TabNavListProps, ref: React.Ref) { } function clearTouchMoving() { - window.clearTimeout(touchMovingRef.current); + if (touchMovingRef.current) { + clearTimeout(touchMovingRef.current); + } } useTouchMove(tabsWrapperRef, (offsetX, offsetY) => { function doMove(setState: React.Dispatch>, offset: number) { setState(value => { const newValue = alignInRange(value + offset); - return newValue; }); } @@ -219,7 +220,7 @@ function TabNavList(props: TabNavListProps, ref: React.Ref) { useEffect(() => { clearTouchMoving(); if (lockAnimation) { - touchMovingRef.current = window.setTimeout(() => { + touchMovingRef.current = setTimeout(() => { setLockAnimation(0); }, 100); } @@ -298,7 +299,7 @@ function TabNavList(props: TabNavListProps, ref: React.Ref) { tabNodeStyle.marginTop = tabBarGutter; } - const tabNodes: React.ReactElement[] = tabs.map((tab, i) => { + const tabNodes = tabs.map((tab, i) => { const { key } = tab; return ( ) { ); if (btnNode) { const [width, height, left, top] = getTabSize(btnNode, listRect); - - newSizes.set(key, { - width, - height, - left, - top, - }); + newSizes.set(key, { width, height, left, top }); } }); return newSizes; @@ -512,6 +507,6 @@ function TabNavList(props: TabNavListProps, ref: React.Ref) { ); /* eslint-enable */ -} +}); -export default React.forwardRef(TabNavList); +export default TabNavList; diff --git a/src/TabPanelList/TabPane.tsx b/src/TabPanelList/TabPane.tsx index fdb4ba60..510520d7 100644 --- a/src/TabPanelList/TabPane.tsx +++ b/src/TabPanelList/TabPane.tsx @@ -21,24 +21,23 @@ export interface TabPaneProps { destroyInactiveTabPane?: boolean; } -const TabPane = React.forwardRef( - ({ prefixCls, className, style, id, active, tabKey, children }, ref) => { - return ( -
- {children} -
- ); - }, -); +const TabPane = React.forwardRef((props, ref) => { + const { prefixCls, className, style, id, active, tabKey, children } = props; + return ( +
+ {children} +
+ ); +}); if (process.env.NODE_ENV !== 'production') { TabPane.displayName = 'TabPane'; diff --git a/src/TabPanelList/index.tsx b/src/TabPanelList/index.tsx index e1171701..0957bbb6 100644 --- a/src/TabPanelList/index.tsx +++ b/src/TabPanelList/index.tsx @@ -1,8 +1,8 @@ -import * as React from 'react'; import classNames from 'classnames'; import CSSMotion from 'rc-motion'; +import * as React from 'react'; +import type { AnimatedConfig, TabPosition } from '../interface'; import TabContext from '../TabContext'; -import type { TabPosition, AnimatedConfig } from '../interface'; import TabPane from './TabPane'; export interface TabPanelListProps { @@ -13,13 +13,8 @@ export interface TabPanelListProps { destroyInactiveTabPane?: boolean; } -export default function TabPanelList({ - id, - activeKey, - animated, - tabPosition, - destroyInactiveTabPane, -}: TabPanelListProps) { +const TabPanelList: React.FC = props => { + const { id, activeKey, animated, tabPosition, destroyInactiveTabPane } = props; const { prefixCls, tabs } = React.useContext(TabContext); const tabPaneAnimated = animated.tabPane; @@ -32,42 +27,44 @@ export default function TabPanelList({ [`${prefixCls}-content-animated`]: tabPaneAnimated, })} > - {tabs.map( - ({ key, forceRender, style: paneStyle, className: paneClassName, destroyInactiveTabPane: itemDestroyInactiveTabPane, ...restTabProps }) => { - const active = key === activeKey; - - return ( - - {({ style: motionStyle, className: motionClassName }, ref) => { - return ( - - ); - }} - - ); - }, - )} + {tabs.map(item => { + const { + key, + forceRender, + style: paneStyle, + className: paneClassName, + destroyInactiveTabPane: itemDestroyInactiveTabPane, + ...restTabProps + } = item; + const active = key === activeKey; + return ( + + {({ style: motionStyle, className: motionClassName }, ref) => ( + + )} + + ); + })} ); -} +}; + +export default TabPanelList; diff --git a/src/Tabs.tsx b/src/Tabs.tsx index 084faa25..457ee8ba 100644 --- a/src/Tabs.tsx +++ b/src/Tabs.tsx @@ -1,10 +1,11 @@ // Accessibility https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Tab_Role -import * as React from 'react'; -import { useEffect, useState } from 'react'; import classNames from 'classnames'; -import isMobile from 'rc-util/lib/isMobile'; import useMergedState from 'rc-util/lib/hooks/useMergedState'; -import TabPanelList from './TabPanelList'; +import isMobile from 'rc-util/lib/isMobile'; +import * as React from 'react'; +import { useEffect, useState } from 'react'; +import useAnimateConfig from './hooks/useAnimateConfig'; +import type { GetIndicatorSize } from './hooks/useIndicator'; import type { AnimatedConfig, EditableConfig, @@ -17,8 +18,7 @@ import type { } from './interface'; import TabContext from './TabContext'; import TabNavListWrapper from './TabNavList/Wrapper'; -import useAnimateConfig from './hooks/useAnimateConfig'; -import type { GetIndicatorSize } from './hooks/useIndicator'; +import TabPanelList from './TabPanelList'; /** * Should added antd: @@ -74,8 +74,8 @@ export interface TabsProps indicatorSize?: GetIndicatorSize; } -function Tabs( - { +const Tabs = React.forwardRef((props, ref) => { + const { id, prefixCls = 'rc-tabs', className, @@ -101,9 +101,7 @@ function Tabs( popupClassName, indicatorSize, ...restProps - }: TabsProps, - ref: React.Ref, -) { + } = props; const tabs = React.useMemo( () => (items || []).filter(item => item && typeof item === 'object' && 'key' in item), [items], @@ -214,11 +212,10 @@ function Tabs( ); -} +}); -const ForwardTabs = React.forwardRef(Tabs); if (process.env.NODE_ENV !== 'production') { - ForwardTabs.displayName = 'Tabs'; + Tabs.displayName = 'Tabs'; } -export default ForwardTabs; +export default Tabs; diff --git a/src/hooks/useIndicator.ts b/src/hooks/useIndicator.ts index 7a0d05d1..984f4eac 100644 --- a/src/hooks/useIndicator.ts +++ b/src/hooks/useIndicator.ts @@ -1,25 +1,20 @@ +import raf from 'rc-util/lib/raf'; import type React from 'react'; import { useEffect, useRef, useState } from 'react'; -import raf from 'rc-util/lib/raf'; import type { TabOffset } from '../interface'; export type GetIndicatorSize = number | ((origin: number) => number); export type UseIndicator = (options: { - activeTabOffset: TabOffset, + activeTabOffset: TabOffset; horizontal: boolean; rtl: boolean; indicatorSize: GetIndicatorSize; }) => { style: React.CSSProperties; -} +}; -const useIndicator: UseIndicator = ({ - activeTabOffset, - horizontal, - rtl, - indicatorSize, - }) => { +const useIndicator: UseIndicator = ({ activeTabOffset, horizontal, rtl, indicatorSize }) => { const [inkStyle, setInkStyle] = useState(); const inkBarRafRef = useRef(); @@ -31,7 +26,7 @@ const useIndicator: UseIndicator = ({ return indicatorSize; } return origin; - } + }; // Delay set ink style to avoid remove tab blink function cleanInkBarRaf() { @@ -68,7 +63,7 @@ const useIndicator: UseIndicator = ({ return { style: inkStyle, - } -} + }; +}; -export default useIndicator; \ No newline at end of file +export default useIndicator; diff --git a/src/hooks/useOffsets.ts b/src/hooks/useOffsets.ts index 2cd683b0..9a62fde3 100644 --- a/src/hooks/useOffsets.ts +++ b/src/hooks/useOffsets.ts @@ -1,5 +1,5 @@ import { useMemo } from 'react'; -import type { TabSizeMap, TabOffsetMap, Tab, TabOffset } from '../interface'; +import type { Tab, TabOffset, TabOffsetMap, TabSizeMap } from '../interface'; const DEFAULT_SIZE = { width: 0, height: 0, left: 0, top: 0 }; diff --git a/src/hooks/useTouchMove.ts b/src/hooks/useTouchMove.ts index dcb126a2..79169957 100644 --- a/src/hooks/useTouchMove.ts +++ b/src/hooks/useTouchMove.ts @@ -1,5 +1,5 @@ import * as React from 'react'; -import { useState, useRef } from 'react'; +import { useRef, useState } from 'react'; type TouchEventHandler = (e: TouchEvent) => void; type WheelEventHandler = (e: WheelEvent) => void; diff --git a/src/index.ts b/src/index.ts index 53020ae1..35e3f768 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ -import Tabs from './Tabs'; import type { TabsProps } from './Tabs'; +import Tabs from './Tabs'; export type { TabsProps }; diff --git a/src/interface.ts b/src/interface.ts index 79b33ab6..a72c2a20 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -1,5 +1,5 @@ -import type React from 'react'; import type { CSSMotionProps } from 'rc-motion'; +import type React from 'react'; import type { TabNavListProps } from './TabNavList'; import type { TabPaneProps } from './TabPanelList/TabPane'; diff --git a/src/util.ts b/src/util.ts index 86269a87..55e13776 100644 --- a/src/util.ts +++ b/src/util.ts @@ -22,6 +22,7 @@ export function stringify(obj: Record Date: Tue, 28 Nov 2023 10:10:50 +0800 Subject: [PATCH 19/65] chore(deps-dev): bump @testing-library/jest-dom from 5.17.0 to 6.1.4 (#689) Bumps [@testing-library/jest-dom](/~https://github.com/testing-library/jest-dom) from 5.17.0 to 6.1.4. - [Release notes](/~https://github.com/testing-library/jest-dom/releases) - [Changelog](/~https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md) - [Commits](/~https://github.com/testing-library/jest-dom/compare/v5.17.0...v6.1.4) --- updated-dependencies: - dependency-name: "@testing-library/jest-dom" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c3f0be24..34154279 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "devDependencies": { "@rc-component/father-plugin": "^1.0.0", "@rc-component/trigger": "^1.10.0", - "@testing-library/jest-dom": "^5.16.4", + "@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "^13.0.0", "@types/classnames": "^2.2.10", "@types/enzyme": "^3.10.5", From ee145ae66edc50355025252243a5b1dc49ff758d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 10:11:14 +0800 Subject: [PATCH 20/65] chore(deps-dev): bump typescript from 4.9.5 to 5.3.2 (#688) Bumps [typescript](/~https://github.com/Microsoft/TypeScript) from 4.9.5 to 5.3.2. - [Release notes](/~https://github.com/Microsoft/TypeScript/releases) - [Commits](/~https://github.com/Microsoft/TypeScript/compare/v4.9.5...v5.3.2) --- updated-dependencies: - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 34154279..9289b0d1 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "react-dom": "^18.0.0", "react-sticky": "^6.0.3", "sortablejs": "^1.7.0", - "typescript": "^4.0.5" + "typescript": "^5.3.2" }, "peerDependencies": { "react": ">=16.9.0", From f2bd7a63e859e8e961730b1e85386279eaa55a6d Mon Sep 17 00:00:00 2001 From: lijianan <574980606@qq.com> Date: Tue, 28 Nov 2023 10:21:49 +0800 Subject: [PATCH 21/65] fix: add span tag to label (#681) * fix: add span tag to label * fix: fix * update snap * fix: fix * test: add test case * Update tests/index.test.tsx Co-authored-by: MadCcc <1075746765@qq.com> --------- Co-authored-by: MadCcc <1075746765@qq.com> --- src/TabNavList/TabNode.tsx | 7 ++++++- tests/index.test.tsx | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/TabNavList/TabNode.tsx b/src/TabNavList/TabNode.tsx index 17de2179..939bc2cf 100644 --- a/src/TabNavList/TabNode.tsx +++ b/src/TabNavList/TabNode.tsx @@ -51,6 +51,11 @@ const TabNode: React.FC = props => { editable.onEdit('remove', { key, event }); } + const labelNode = React.useMemo( + () => (icon && typeof label === 'string' ? {label} : label), + [label, icon], + ); + const node: React.ReactElement = (
= props => { onFocus={onFocus} > {icon && {icon}} - {label} + {label && labelNode}
{/* Remove Button */} diff --git a/tests/index.test.tsx b/tests/index.test.tsx index dc91c837..70f0e7ad 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -638,4 +638,14 @@ describe('Tabs.Basic', () => { await waitFakeTimer(); expect(container.querySelector('.rc-tabs-ink-bar')).toHaveStyle({ width: '18px' }); }); + + it('Add span to text label when have icon', () => { + const selectors = '.rc-tabs-tab .rc-tabs-tab-btn span'; + const { container, rerender } = render( + , + ); + expect(container.querySelectorAll(selectors).length).toBe(2); + rerender(test, icon: 'test' }]} />); + expect(container.querySelectorAll(selectors).length).toBe(1); + }); }); From 296ba5a36452937b169334c00427d1b17924aa1d Mon Sep 17 00:00:00 2001 From: MadCcc <1075746765@qq.com> Date: Tue, 28 Nov 2023 10:27:28 +0800 Subject: [PATCH 22/65] v12.14.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9289b0d1..61ca207a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-tabs", - "version": "12.14.0", + "version": "12.14.1", "description": "tabs ui component for react", "keywords": [ "react", From 8f2734e143b8ab512a96bb97c065253553585158 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 07:38:01 +0800 Subject: [PATCH 23/65] chore(deps-dev): bump np from 7.7.0 to 9.0.0 (#685) Bumps [np](/~https://github.com/sindresorhus/np) from 7.7.0 to 9.0.0. - [Release notes](/~https://github.com/sindresorhus/np/releases) - [Commits](/~https://github.com/sindresorhus/np/compare/v7.7.0...v9.0.0) --- updated-dependencies: - dependency-name: np dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 61ca207a..29bbc911 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "history": "^5.3.0", "immutability-helper": "^3.0.1", "less": "^4.1.3", - "np": "^7.5.0", + "np": "^9.0.0", "preact-compat": "^3.16.0", "rc-test": "^7.0.14", "react": "^18.0.0", From 364f6e30080126dfa4d969c5336a5b3757467f5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 07:38:14 +0800 Subject: [PATCH 24/65] chore(deps-dev): bump gh-pages from 5.0.0 to 6.1.0 (#684) Bumps [gh-pages](/~https://github.com/tschaub/gh-pages) from 5.0.0 to 6.1.0. - [Release notes](/~https://github.com/tschaub/gh-pages/releases) - [Changelog](/~https://github.com/tschaub/gh-pages/blob/main/changelog.md) - [Commits](/~https://github.com/tschaub/gh-pages/compare/v5.0.0...v6.1.0) --- updated-dependencies: - dependency-name: gh-pages dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29bbc911..91c2d485 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "eslint-plugin-unicorn": "^49.0.0", "fastclick": "~1.0.6", "father": "^4.0.0", - "gh-pages": "^5.0.0", + "gh-pages": "^6.1.0", "history": "^5.3.0", "immutability-helper": "^3.0.1", "less": "^4.1.3", From 3f1eea62ae59697f8fc9729d2f7d4a8e2d8650de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 07:42:19 +0800 Subject: [PATCH 25/65] chore(deps-dev): bump @testing-library/react from 13.4.0 to 14.1.2 (#686) Bumps [@testing-library/react](/~https://github.com/testing-library/react-testing-library) from 13.4.0 to 14.1.2. - [Release notes](/~https://github.com/testing-library/react-testing-library/releases) - [Changelog](/~https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md) - [Commits](/~https://github.com/testing-library/react-testing-library/compare/v13.4.0...v14.1.2) --- updated-dependencies: - dependency-name: "@testing-library/react" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: lijianan <574980606@qq.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 91c2d485..56eafec3 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,8 @@ "devDependencies": { "@rc-component/father-plugin": "^1.0.0", "@rc-component/trigger": "^1.10.0", + "@testing-library/react": "^14.1.2", "@testing-library/jest-dom": "^6.1.4", - "@testing-library/react": "^13.0.0", "@types/classnames": "^2.2.10", "@types/enzyme": "^3.10.5", "@types/jest": "^29.4.0", From a99a9ed530501f27a56cc10c9fd99aca037487d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 08:00:14 +0800 Subject: [PATCH 26/65] chore(deps-dev): bump @umijs/fabric from 2.14.1 to 4.0.1 (#687) * chore(deps-dev): bump @umijs/fabric from 2.14.1 to 4.0.1 Bumps [@umijs/fabric](/~https://github.com/umijs/fabric) from 2.14.1 to 4.0.1. - [Release notes](/~https://github.com/umijs/fabric/releases) - [Commits](/~https://github.com/umijs/fabric/compare/v2.14.1...v4.0.1) --- updated-dependencies: - dependency-name: "@umijs/fabric" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * fix: fix lint --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: lijianan <574980606@qq.com> --- docs/examples/indicator.tsx | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/examples/indicator.tsx b/docs/examples/indicator.tsx index c204587b..17f05dfc 100644 --- a/docs/examples/indicator.tsx +++ b/docs/examples/indicator.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import Tabs from'../../src'; import '../../assets/index.less'; +import Tabs from '../../src'; export default () => { - const [destroy, setDestroy] = React.useState(false); - const [items, setItems] = React.useState([ + const [destroy] = React.useState(false); + const [items] = React.useState([ { label: 'Light', key: 'light', @@ -29,7 +29,7 @@ export default () => { return ( - origin - 16} /> + origin - 16} /> ); }; diff --git a/package.json b/package.json index 56eafec3..308c4966 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@types/keyv": "4.2.0", "@types/react": "^17.0.14", "@types/react-dom": "^18.0.11", - "@umijs/fabric": "^2.3.1", + "@umijs/fabric": "^4.0.1", "coveralls": "^3.0.6", "cross-env": "^7.0.2", "dumi": "^2.0.0", From 9bde7d1a499e6fdbdfdbd4c8cf74e56f56282adb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 08:03:13 +0800 Subject: [PATCH 27/65] chore(deps-dev): bump @types/react from 17.0.71 to 18.2.42 (#690) * chore(deps-dev): bump @types/react from 17.0.71 to 18.2.42 Bumps [@types/react](/~https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 17.0.71 to 18.2.42. - [Release notes](/~https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](/~https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) --- updated-dependencies: - dependency-name: "@types/react" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * fix: fix lint --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: lijianan <574980606@qq.com> --- package.json | 2 +- src/TabNavList/index.tsx | 4 ++-- src/hooks/useOffsets.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 308c4966..51248b60 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@types/enzyme": "^3.10.5", "@types/jest": "^29.4.0", "@types/keyv": "4.2.0", - "@types/react": "^17.0.14", + "@types/react": "^18.2.42", "@types/react-dom": "^18.0.11", "@umijs/fabric": "^4.0.1", "coveralls": "^3.0.6", diff --git a/src/TabNavList/index.tsx b/src/TabNavList/index.tsx index cae9a3d1..507fb543 100644 --- a/src/TabNavList/index.tsx +++ b/src/TabNavList/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import classNames from 'classnames'; import ResizeObserver from 'rc-resize-observer'; import useEvent from 'rc-util/lib/hooks/useEvent'; @@ -399,13 +400,12 @@ const TabNavList = React.forwardRef((props, ref // ========================= Effect ======================== useEffect(() => { scrollToTab(); - // eslint-disable-next-line }, [ activeKey, transformMin, transformMax, stringify(activeTabOffset), - stringify(tabOffsets), + stringify(tabOffsets as any), tabPositionTopOrBottom, ]); diff --git a/src/hooks/useOffsets.ts b/src/hooks/useOffsets.ts index 9a62fde3..ee694406 100644 --- a/src/hooks/useOffsets.ts +++ b/src/hooks/useOffsets.ts @@ -4,7 +4,7 @@ import type { Tab, TabOffset, TabOffsetMap, TabSizeMap } from '../interface'; const DEFAULT_SIZE = { width: 0, height: 0, left: 0, top: 0 }; export default function useOffsets(tabs: Tab[], tabSizes: TabSizeMap, holderScrollWidth: number) { - return useMemo(() => { + return useMemo(() => { const map: TabOffsetMap = new Map(); const lastOffset = tabSizes.get(tabs[0]?.key) || DEFAULT_SIZE; From c61f65a12726304a092d1fe75aa32df6e33867b2 Mon Sep 17 00:00:00 2001 From: lijianan <574980606@qq.com> Date: Thu, 7 Dec 2023 14:14:55 +0800 Subject: [PATCH 28/65] feat: Tabs support indicatorPosition prop (#691) * feat: Tabs support indicatorPosition prop * test: add test case * update demo * test: add test cas * revert function * Update src/hooks/useIndicator.ts Co-authored-by: MadCcc <1075746765@qq.com> * fix: fix * fix: fix --------- Co-authored-by: MadCcc <1075746765@qq.com> --- .dumirc.ts | 2 +- assets/position.less | 3 +- docs/examples/indicator.tsx | 88 ++++++++++++++++++++----------- src/TabNavList/Wrapper.tsx | 1 - src/TabNavList/index.tsx | 6 ++- src/Tabs.tsx | 11 ++-- src/hooks/useIndicator.ts | 72 +++++++++++++++---------- src/interface.ts | 1 + tests/index.test.tsx | 73 +++++++++++++++++++++++++ tests/operation-overflow.test.tsx | 7 +-- 10 files changed, 193 insertions(+), 71 deletions(-) diff --git a/.dumirc.ts b/.dumirc.ts index 92fcf489..d31eaee7 100644 --- a/.dumirc.ts +++ b/.dumirc.ts @@ -5,4 +5,4 @@ export default defineConfig({ name: 'Tabs', }, mfsu: false, -}); \ No newline at end of file +}); diff --git a/assets/position.less b/assets/position.less index e841a7e1..8b64ea20 100644 --- a/assets/position.less +++ b/assets/position.less @@ -52,7 +52,8 @@ flex-direction: column; min-width: 50px; - &-list, &-operations { + &-list, + &-operations { flex: 1 0 auto; // fix safari scroll problem flex-direction: column; } diff --git a/docs/examples/indicator.tsx b/docs/examples/indicator.tsx index 17f05dfc..18ea104f 100644 --- a/docs/examples/indicator.tsx +++ b/docs/examples/indicator.tsx @@ -1,35 +1,63 @@ import React from 'react'; import '../../assets/index.less'; +import type { TabsProps } from '../../src'; import Tabs from '../../src'; -export default () => { - const [destroy] = React.useState(false); - const [items] = React.useState([ - { - label: 'Light', - key: 'light', - children: 'Light!', - }, - { - label: 'Bamboo', - key: 'bamboo', - children: 'Bamboo!', - }, - { - label: 'Cute', - key: 'cute', - children: 'Cute!', - disabled: true, - }, - ]); +const items: TabsProps['items'] = [ + { + label: 'Light', + key: 'light', + children: 'Light!', + }, + { + label: 'Bamboo', + key: 'bamboo', + children: 'Bamboo!', + }, + { + label: 'Cute', + key: 'cute', + children: 'Cute!', + }, +]; - if (destroy) { - return null; - } - - return ( - - origin - 16} /> - - ); -}; +export default () => ( + <> + origin - 20} + indicatorAlign="start" + /> + origin - 20} + indicatorAlign="center" + /> + origin - 20} + indicatorAlign="end" + /> + origin - 20} + indicatorAlign="start" + /> + origin - 20} + indicatorAlign="center" + /> + origin - 20} + indicatorAlign="end" + /> + +); diff --git a/src/TabNavList/Wrapper.tsx b/src/TabNavList/Wrapper.tsx index 63d0ee8a..a2b4bd50 100644 --- a/src/TabNavList/Wrapper.tsx +++ b/src/TabNavList/Wrapper.tsx @@ -15,7 +15,6 @@ const TabNavListWrapper: React.FC = ({ renderTabBar, ... if (renderTabBar) { const tabNavBarProps = { ...restProps, - // Legacy support. We do not use this actually panes: tabs.map(({ label, key, ...restTabProps }) => ( diff --git a/src/TabNavList/index.tsx b/src/TabNavList/index.tsx index 507fb543..0cccdfc4 100644 --- a/src/TabNavList/index.tsx +++ b/src/TabNavList/index.tsx @@ -5,6 +5,7 @@ import useEvent from 'rc-util/lib/hooks/useEvent'; import { useComposeRef } from 'rc-util/lib/ref'; import * as React from 'react'; import { useEffect, useRef, useState } from 'react'; +import TabContext from '../TabContext'; import type { GetIndicatorSize } from '../hooks/useIndicator'; import useIndicator from '../hooks/useIndicator'; import useOffsets from '../hooks/useOffsets'; @@ -23,7 +24,6 @@ import type { TabSizeMap, TabsLocale, } from '../interface'; -import TabContext from '../TabContext'; import { genDataNodeKey, stringify } from '../util'; import AddButton from './AddButton'; import ExtraContent from './ExtraContent'; @@ -52,6 +52,7 @@ export interface TabNavListProps { getPopupContainer?: (node: HTMLElement) => HTMLElement; popupClassName?: string; indicatorSize?: GetIndicatorSize; + indicatorAlign?: 'start' | 'center' | 'end'; } const getTabSize = (tab: HTMLElement, containerRect: { x: number; y: number }) => { @@ -106,6 +107,7 @@ const TabNavList = React.forwardRef((props, ref onTabClick, onTabScroll, indicatorSize, + indicatorAlign, } = props; const { prefixCls, tabs } = React.useContext(TabContext); const containerRef = useRef(null); @@ -395,6 +397,7 @@ const TabNavList = React.forwardRef((props, ref horizontal: tabPositionTopOrBottom, rtl, indicatorSize, + indicatorAlign, }); // ========================= Effect ======================== @@ -480,7 +483,6 @@ const TabNavList = React.forwardRef((props, ref visibility: hasDropdown ? 'hidden' : null, }} /> -
((props, ref) => { @@ -100,9 +101,10 @@ const Tabs = React.forwardRef((props, ref) => { getPopupContainer, popupClassName, indicatorSize, + indicatorAlign = 'center', ...restProps } = props; - const tabs = React.useMemo( + const tabs = React.useMemo( () => (items || []).filter(item => item && typeof item === 'object' && 'key' in item), [items], ); @@ -184,6 +186,7 @@ const Tabs = React.forwardRef((props, ref) => { getPopupContainer, popupClassName, indicatorSize, + indicatorAlign, }; return ( diff --git a/src/hooks/useIndicator.ts b/src/hooks/useIndicator.ts index 984f4eac..6a9ee732 100644 --- a/src/hooks/useIndicator.ts +++ b/src/hooks/useIndicator.ts @@ -1,32 +1,34 @@ import raf from 'rc-util/lib/raf'; -import type React from 'react'; -import { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import type { TabOffset } from '../interface'; export type GetIndicatorSize = number | ((origin: number) => number); -export type UseIndicator = (options: { +interface UseIndicatorOptions { activeTabOffset: TabOffset; horizontal: boolean; rtl: boolean; indicatorSize: GetIndicatorSize; -}) => { - style: React.CSSProperties; -}; + indicatorAlign: 'start' | 'center' | 'end'; +} -const useIndicator: UseIndicator = ({ activeTabOffset, horizontal, rtl, indicatorSize }) => { +const useIndicator = (options: UseIndicatorOptions) => { + const { activeTabOffset, horizontal, rtl, indicatorSize, indicatorAlign } = options; const [inkStyle, setInkStyle] = useState(); const inkBarRafRef = useRef(); - const getLength = (origin: number) => { - if (typeof indicatorSize === 'function') { - return indicatorSize(origin); - } - if (typeof indicatorSize === 'number') { - return indicatorSize; - } - return origin; - }; + const getLength = React.useCallback( + (origin: number) => { + if (typeof indicatorSize === 'function') { + return indicatorSize(origin); + } + if (typeof indicatorSize === 'number') { + return indicatorSize; + } + return origin; + }, + [indicatorSize], + ); // Delay set ink style to avoid remove tab blink function cleanInkBarRaf() { @@ -38,18 +40,32 @@ const useIndicator: UseIndicator = ({ activeTabOffset, horizontal, rtl, indicato if (activeTabOffset) { if (horizontal) { - if (rtl) { - newInkStyle.right = activeTabOffset.right + activeTabOffset.width / 2; - newInkStyle.transform = 'translateX(50%)'; - } else { - newInkStyle.left = activeTabOffset.left + activeTabOffset.width / 2; - newInkStyle.transform = 'translateX(-50%)'; - } newInkStyle.width = getLength(activeTabOffset.width); + const key = rtl ? 'right' : 'left'; + if (indicatorAlign === 'start') { + newInkStyle[key] = activeTabOffset[key]; + } + if (indicatorAlign === 'center') { + newInkStyle[key] = activeTabOffset[key] + activeTabOffset.width / 2; + newInkStyle.transform = rtl ? 'translateX(50%)' : 'translateX(-50%)'; + } + if (indicatorAlign === 'end') { + newInkStyle[key] = activeTabOffset[key] + activeTabOffset.width; + newInkStyle.transform = 'translateX(-100%)'; + } } else { - newInkStyle.top = activeTabOffset.top + activeTabOffset.height / 2; - newInkStyle.transform = 'translateY(-50%)'; newInkStyle.height = getLength(activeTabOffset.height); + if (indicatorAlign === 'start') { + newInkStyle.top = activeTabOffset.top; + } + if (indicatorAlign === 'center') { + newInkStyle.top = activeTabOffset.top + activeTabOffset.height / 2; + newInkStyle.transform = 'translateY(-50%)'; + } + if (indicatorAlign === 'end') { + newInkStyle.top = activeTabOffset.top + activeTabOffset.height; + newInkStyle.transform = 'translateY(-100%)'; + } } } @@ -59,11 +75,9 @@ const useIndicator: UseIndicator = ({ activeTabOffset, horizontal, rtl, indicato }); return cleanInkBarRaf; - }, [activeTabOffset, horizontal, rtl, indicatorSize]); + }, [activeTabOffset, horizontal, rtl, indicatorSize, indicatorAlign, getLength]); - return { - style: inkStyle, - }; + return { style: inkStyle }; }; export default useIndicator; diff --git a/src/interface.ts b/src/interface.ts index a72c2a20..ae7d6a9e 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -17,6 +17,7 @@ export interface TabOffset { right: number; top: number; } + export type TabOffsetMap = Map; export type TabPosition = 'left' | 'right' | 'top' | 'bottom'; diff --git a/tests/index.test.tsx b/tests/index.test.tsx index 70f0e7ad..60753a34 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -648,4 +648,77 @@ describe('Tabs.Basic', () => { rerender(test
, icon: 'test' }]} />); expect(container.querySelectorAll(selectors).length).toBe(1); }); + + it('support indicatorAlign', async () => { + const { container: startContainer } = render( + origin - 10} + indicatorAlign="start" + />, + ); + const { container: centerContainer } = render( + origin - 10} + indicatorAlign="center" + />, + ); + const { container: endContainer } = render( + origin - 10} + indicatorAlign="end" + />, + ); + + await waitFakeTimer(); + + const selectors = '.rc-tabs .rc-tabs-nav .rc-tabs-nav-list .rc-tabs-ink-bar'; + + const startBar = startContainer.querySelector(selectors); + const centerBar = centerContainer.querySelector(selectors); + const endBar = endContainer.querySelector(selectors); + + expect(parseInt(startBar.style.left)).toBeLessThanOrEqual(parseInt(centerBar.style.left)); + expect(parseInt(centerBar.style.left)).toBeLessThanOrEqual(parseInt(endBar.style.left)); + }); + + it('support indicatorAlign when tabPosition=left', async () => { + const { container: startContainer } = render( + origin - 10} + indicatorAlign="start" + />, + ); + const { container: centerContainer } = render( + origin - 10} + indicatorAlign="center" + />, + ); + const { container: endContainer } = render( + origin - 10} + indicatorAlign="end" + />, + ); + + await waitFakeTimer(); + + const selectors = '.rc-tabs .rc-tabs-nav .rc-tabs-nav-list .rc-tabs-ink-bar'; + + const startBar = startContainer.querySelector(selectors); + const centerBar = centerContainer.querySelector(selectors); + const endBar = endContainer.querySelector(selectors); + + expect(parseInt(startBar.style.top)).toBeLessThanOrEqual(parseInt(centerBar.style.top)); + expect(parseInt(centerBar.style.top)).toBeLessThanOrEqual(parseInt(endBar.style.top)); + }); }); diff --git a/tests/operation-overflow.test.tsx b/tests/operation-overflow.test.tsx index a5b87eed..b48abe0c 100644 --- a/tests/operation-overflow.test.tsx +++ b/tests/operation-overflow.test.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-invalid-this */ import { render } from '@testing-library/react'; import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; import { act } from 'react-dom/test-utils'; @@ -53,9 +54,9 @@ describe('Tabs.Operation-Overflow', () => { act(() => { jest.runAllTimers(); }); - expect( - container.querySelector('.rc-tabs-nav-operations'), - ).not.toHaveClass('rc-tabs-nav-operations-hidden'); + expect(container.querySelector('.rc-tabs-nav-operations')).not.toHaveClass( + 'rc-tabs-nav-operations-hidden', + ); unmount(); From e54191e7662e175ed8fe564292bf6525423a4ce3 Mon Sep 17 00:00:00 2001 From: MadCcc <1075746765@qq.com> Date: Thu, 7 Dec 2023 14:25:24 +0800 Subject: [PATCH 29/65] v12.15.0 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 51248b60..e744c8c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-tabs", - "version": "12.14.1", + "version": "12.15.0", "description": "tabs ui component for react", "keywords": [ "react", @@ -48,8 +48,8 @@ "devDependencies": { "@rc-component/father-plugin": "^1.0.0", "@rc-component/trigger": "^1.10.0", - "@testing-library/react": "^14.1.2", "@testing-library/jest-dom": "^6.1.4", + "@testing-library/react": "^14.1.2", "@types/classnames": "^2.2.10", "@types/enzyme": "^3.10.5", "@types/jest": "^29.4.0", From 7c3565007d3563eac82af28fb545995533e203a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 06:45:32 +0800 Subject: [PATCH 30/65] chore(deps-dev): bump eslint-plugin-unicorn from 49.0.0 to 50.0.1 (#693) Bumps [eslint-plugin-unicorn](/~https://github.com/sindresorhus/eslint-plugin-unicorn) from 49.0.0 to 50.0.1. - [Release notes](/~https://github.com/sindresorhus/eslint-plugin-unicorn/releases) - [Commits](/~https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v49.0.0...v50.0.1) --- updated-dependencies: - dependency-name: eslint-plugin-unicorn dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e744c8c5..d32ad16b 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "dumi": "^2.0.0", "eslint": "^8.54.0", "eslint-plugin-jest": "^27.6.0", - "eslint-plugin-unicorn": "^49.0.0", + "eslint-plugin-unicorn": "^50.0.1", "fastclick": "~1.0.6", "father": "^4.0.0", "gh-pages": "^6.1.0", From ba563b4a682560e5bcb757a26630afd33034dbf3 Mon Sep 17 00:00:00 2001 From: Iliyas <122092838+s-iliyas@users.noreply.github.com> Date: Wed, 3 Jan 2024 04:23:11 +0530 Subject: [PATCH 31/65] Update README.md (#669) Co-authored-by: lijianan <574980606@qq.com> --- README.md | 112 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 84 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 96b2f5f5..0599bff0 100644 --- a/README.md +++ b/README.md @@ -41,24 +41,53 @@ online example: https://tabs.react-component.now.sh/ ## Usage -```js -import Tabs, { TabPane } from 'rc-tabs'; - -var callback = function(key) {}; - -React.render( - - - first - - - second - - - third - - , - document.getElementById('t2'), +```tsx +import Tabs from 'rc-tabs'; +import ReactDom from 'react-dom'; + +const callback = (key) => { + console.log(key); +}; + +const items = [ + { + key: '1', + label: 'Google', + children: ( +
+

Lorem Ipsum is simply dummy text of the printing and typesetting

+
+ ), + }, + { + key: '2', + label:

Amazon

, + children: + 'Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...', + disabled: true, + }, + { + key: '3', + label:

Twitter

, + children: ( +
+ "There is no one who loves pain itself, who seeks after it and wants to have it, simply + because it is pain..." +
+ ), + }, +]; + +ReactDom.render( + , + root, ); ``` @@ -68,25 +97,52 @@ React.render( | name | type | default | description | | --- | --- | --- | --- | +| prefixCls | string | `'rc-tabs'` | prefix class name, use to custom style | +| className | string | - | to define a class name for an element | +| style | CSS properties | - | object with css properties for styling | +| items | TabItem[] | [] | configure tab content | +| id | string | - | unique identifier | +| defaultActiveKey | string | - | initial active tabPanel's key if activeKey is absent | | activeKey | string | - | current active tabPanel's key | +| direction | `'ltr' or 'rtl'` | `'ltr'` | Layout direction of tabs component | | animated | boolean \| { inkBar: boolean, tabPane: boolean } | `{ inkBar: true, tabPane: false }` | config animation | -| defaultActiveKey | string | - | initial active tabPanel's key if activeKey is absent | -| destroyInactiveTabPane | boolean | false | whether destroy inactive TabPane when change tab | -| direction | `'ltr' | 'rlt'` | `'ltr'` | Layout direction of tabs component | -| editable | { onEdit(type: 'add' | 'remove', info: { key, event }), showAdd: boolean, removeIcon: ReactNode, addIcon: ReactNode } | - | config tab editable | -| locale | { dropdownAriaLabel: string, removeAriaLabel: string, addAriaLabel: string } | - | Accessibility locale help text | -| moreIcon | ReactNode | - | collapse icon | +| renderTabBar | (props, TabBarComponent) => ReactElement | - | How to render tab bar | +| tabBarExtraContent | ReactNode \| `{ left: ReactNode, right: ReactNode }` | - | config extra content | | tabBarGutter | number | 0 | config tab bar gutter | | tabBarPosition | `'left' \| 'right' \| 'top' \| 'bottom'` | `'top'` | tab nav 's position | | tabBarStyle | style | - | tab nav style | -| tabBarExtraContent | ReactNode \| `{ left: ReactNode, right: ReactNode }` | - | config extra content | -| renderTabBar | (props, TabBarComponent) => ReactElement | - | How to render tab bar | -| prefixCls | string | `'rc-tabs'` | prefix class name, use to custom style | +| tabPosition | `'left' or 'right' or 'top' or 'bottom'` | `'top'` | tab nav 's position | +| destroyInactiveTabPane | boolean | false | whether destroy inactive TabPane when change tab | | onChange | (key) => void | - | called when tabPanel is changed | | onTabClick | (key) => void | - | called when tab click | | onTabScroll | ({ direction }) => void | - | called when tab scroll | +| editable | { onEdit(type: 'add' | 'remove', info: { key, event }), showAdd: boolean, removeIcon: ReactNode, addIcon: ReactNode } | - | config tab editable | +| locale | { dropdownAriaLabel: string, removeAriaLabel: string, addAriaLabel: string } | - | Accessibility locale help text | +| moreIcon | ReactNode | - | collapse icon | + +### TabItem + +| name | type | default | description | +| --- | --- | --- | --- | +| key | string | - | corresponding to activeKey, should be unique | +| label | string | - | TabPane's head display text | +| tab | ReactNode | - | current tab's title corresponding to current tabPane | +| className | string | - | to define a class name for an element | +| style | CSS properties | - | object with css properties for styling | +| disabled | boolean | false | set TabPane disabled | +| children | ReactNode | - | TabPane's head display content | +| forceRender | boolean | false | forced render of content in tabs, not lazy render after clicking on tabs | +| closable | boolean | false | closable feature of tab item | +| closeIcon | ReactNode | - | Config close icon | +| prefixCls | string | `'rc-tabs-tab'` | prefix class name, use to custom style | +| id | string | - | unique identifier | +| animated | boolean \| { inkBar: boolean, tabPane: boolean } | `{ inkBar: true, tabPane: false }` | config animation | +| destroyInactiveTabPane | boolean | false | whether destroy inactive TabPane when change tab | +| active | boolean | false | active feature of tab item | +| tabKey | string | - | key linked to tab | + -### TabPane +### TabPane(support in older versions) | name | type | default | description | | --- | --- | --- | --- | From 28b061b620b96c96449a5f1b22fb173bd731ba90 Mon Sep 17 00:00:00 2001 From: lijianan <574980606@qq.com> Date: Thu, 4 Jan 2024 10:21:26 +0800 Subject: [PATCH 32/65] refactor: refactor indicator props (#695) * refactor: refactor indicator props * update demo * test: fix test case --- docs/examples/indicator.tsx | 18 ++++++------------ src/TabNavList/index.tsx | 20 ++++++++++++++++---- src/Tabs.tsx | 11 +++++++---- src/hooks/useIndicator.ts | 32 +++++++++++++++++--------------- tests/index.test.tsx | 18 ++++++------------ 5 files changed, 52 insertions(+), 47 deletions(-) diff --git a/docs/examples/indicator.tsx b/docs/examples/indicator.tsx index 18ea104f..90642451 100644 --- a/docs/examples/indicator.tsx +++ b/docs/examples/indicator.tsx @@ -26,38 +26,32 @@ export default () => ( origin - 20} - indicatorAlign="start" + indicator={{ size: origin => origin - 20, align: 'start' }} /> origin - 20} - indicatorAlign="center" + indicator={{ size: origin => origin - 20, align: 'center' }} /> origin - 20} - indicatorAlign="end" + indicator={{ size: origin => origin - 20, align: 'end' }} /> origin - 20} - indicatorAlign="start" + indicator={{ size: origin => origin - 20, align: 'start' }} /> origin - 20} - indicatorAlign="center" + indicator={{ size: origin => origin - 20, align: 'center' }} /> origin - 20} - indicatorAlign="end" + indicator={{ size: origin => origin - 20, align: 'end' }} /> ); diff --git a/src/TabNavList/index.tsx b/src/TabNavList/index.tsx index 0cccdfc4..2f83b907 100644 --- a/src/TabNavList/index.tsx +++ b/src/TabNavList/index.tsx @@ -51,8 +51,13 @@ export interface TabNavListProps { children?: (node: React.ReactElement) => React.ReactElement; getPopupContainer?: (node: HTMLElement) => HTMLElement; popupClassName?: string; + + /** @deprecated Use `indicator={ size: ... }` instead */ indicatorSize?: GetIndicatorSize; - indicatorAlign?: 'start' | 'center' | 'end'; + indicator?: { + size?: GetIndicatorSize; + align?: 'start' | 'center' | 'end'; + }; } const getTabSize = (tab: HTMLElement, containerRect: { x: number; y: number }) => { @@ -107,8 +112,13 @@ const TabNavList = React.forwardRef((props, ref onTabClick, onTabScroll, indicatorSize, - indicatorAlign, + indicator, } = props; + + const mergedIndicatorSize = indicator?.size || indicatorSize; + + const mergedIndicatorAlign = indicator?.align || 'center'; + const { prefixCls, tabs } = React.useContext(TabContext); const containerRef = useRef(null); const extraLeftRef = useRef(null); @@ -396,8 +406,10 @@ const TabNavList = React.forwardRef((props, ref activeTabOffset, horizontal: tabPositionTopOrBottom, rtl, - indicatorSize, - indicatorAlign, + indicator: { + size: mergedIndicatorSize, + align: mergedIndicatorAlign, + }, }); // ========================= Effect ======================== diff --git a/src/Tabs.tsx b/src/Tabs.tsx index bb8ae60c..d13e0479 100644 --- a/src/Tabs.tsx +++ b/src/Tabs.tsx @@ -70,9 +70,12 @@ export interface TabsProps popupClassName?: string; - // Indicator + /** @deprecated Use `indicator={ size: ... }` instead */ indicatorSize?: GetIndicatorSize; - indicatorAlign?: 'start' | 'center' | 'end'; + indicator?: { + size?: GetIndicatorSize; + align?: 'start' | 'center' | 'end'; + }; } const Tabs = React.forwardRef((props, ref) => { @@ -101,7 +104,7 @@ const Tabs = React.forwardRef((props, ref) => { getPopupContainer, popupClassName, indicatorSize, - indicatorAlign = 'center', + indicator, ...restProps } = props; const tabs = React.useMemo( @@ -186,7 +189,7 @@ const Tabs = React.forwardRef((props, ref) => { getPopupContainer, popupClassName, indicatorSize, - indicatorAlign, + indicator, }; return ( diff --git a/src/hooks/useIndicator.ts b/src/hooks/useIndicator.ts index 6a9ee732..172bd523 100644 --- a/src/hooks/useIndicator.ts +++ b/src/hooks/useIndicator.ts @@ -8,26 +8,28 @@ interface UseIndicatorOptions { activeTabOffset: TabOffset; horizontal: boolean; rtl: boolean; - indicatorSize: GetIndicatorSize; - indicatorAlign: 'start' | 'center' | 'end'; + indicator?: { + size?: GetIndicatorSize; + align?: 'start' | 'center' | 'end'; + }; } const useIndicator = (options: UseIndicatorOptions) => { - const { activeTabOffset, horizontal, rtl, indicatorSize, indicatorAlign } = options; + const { activeTabOffset, horizontal, rtl, indicator } = options; const [inkStyle, setInkStyle] = useState(); const inkBarRafRef = useRef(); const getLength = React.useCallback( (origin: number) => { - if (typeof indicatorSize === 'function') { - return indicatorSize(origin); + if (typeof indicator?.size === 'function') { + return indicator?.size(origin); } - if (typeof indicatorSize === 'number') { - return indicatorSize; + if (typeof indicator?.size === 'number') { + return indicator?.size; } return origin; }, - [indicatorSize], + [indicator], ); // Delay set ink style to avoid remove tab blink @@ -42,27 +44,27 @@ const useIndicator = (options: UseIndicatorOptions) => { if (horizontal) { newInkStyle.width = getLength(activeTabOffset.width); const key = rtl ? 'right' : 'left'; - if (indicatorAlign === 'start') { + if (indicator?.align === 'start') { newInkStyle[key] = activeTabOffset[key]; } - if (indicatorAlign === 'center') { + if (indicator?.align === 'center') { newInkStyle[key] = activeTabOffset[key] + activeTabOffset.width / 2; newInkStyle.transform = rtl ? 'translateX(50%)' : 'translateX(-50%)'; } - if (indicatorAlign === 'end') { + if (indicator?.align === 'end') { newInkStyle[key] = activeTabOffset[key] + activeTabOffset.width; newInkStyle.transform = 'translateX(-100%)'; } } else { newInkStyle.height = getLength(activeTabOffset.height); - if (indicatorAlign === 'start') { + if (indicator?.align === 'start') { newInkStyle.top = activeTabOffset.top; } - if (indicatorAlign === 'center') { + if (indicator?.align === 'center') { newInkStyle.top = activeTabOffset.top + activeTabOffset.height / 2; newInkStyle.transform = 'translateY(-50%)'; } - if (indicatorAlign === 'end') { + if (indicator?.align === 'end') { newInkStyle.top = activeTabOffset.top + activeTabOffset.height; newInkStyle.transform = 'translateY(-100%)'; } @@ -75,7 +77,7 @@ const useIndicator = (options: UseIndicatorOptions) => { }); return cleanInkBarRaf; - }, [activeTabOffset, horizontal, rtl, indicatorSize, indicatorAlign, getLength]); + }, [activeTabOffset, horizontal, rtl, indicator?.align, getLength]); return { style: inkStyle }; }; diff --git a/tests/index.test.tsx b/tests/index.test.tsx index 60753a34..d0f90698 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -653,22 +653,19 @@ describe('Tabs.Basic', () => { const { container: startContainer } = render( origin - 10} - indicatorAlign="start" + indicator={{ size: origin => origin - 20, align: 'start' }} />, ); const { container: centerContainer } = render( origin - 10} - indicatorAlign="center" + indicator={{ size: origin => origin - 20, align: 'center' }} />, ); const { container: endContainer } = render( origin - 10} - indicatorAlign="end" + indicator={{ size: origin => origin - 20, align: 'end' }} />, ); @@ -689,24 +686,21 @@ describe('Tabs.Basic', () => { origin - 10} - indicatorAlign="start" + indicator={{ size: origin => origin - 20, align: 'start' }} />, ); const { container: centerContainer } = render( origin - 10} - indicatorAlign="center" + indicator={{ size: origin => origin - 20, align: 'center' }} />, ); const { container: endContainer } = render( origin - 10} - indicatorAlign="end" + indicator={{ size: origin => origin - 20, align: 'end' }} />, ); From 21b116f6190df4ad24a5127d4ed186918be1b457 Mon Sep 17 00:00:00 2001 From: afc163 Date: Thu, 4 Jan 2024 10:26:14 +0800 Subject: [PATCH 33/65] 13.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d32ad16b..3046a0d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-tabs", - "version": "12.15.0", + "version": "13.0.0", "description": "tabs ui component for react", "keywords": [ "react", From 53b48e5a7f684d79f9172ca43845f619e373da72 Mon Sep 17 00:00:00 2001 From: lijianan <574980606@qq.com> Date: Thu, 4 Jan 2024 23:06:52 +0800 Subject: [PATCH 34/65] chore: rm compatible logic (#696) --- src/TabNavList/index.tsx | 13 +------------ src/Tabs.tsx | 6 ------ src/hooks/useIndicator.ts | 29 ++++++++++++++++------------- tests/index.test.tsx | 4 ++-- 4 files changed, 19 insertions(+), 33 deletions(-) diff --git a/src/TabNavList/index.tsx b/src/TabNavList/index.tsx index 2f83b907..124583e1 100644 --- a/src/TabNavList/index.tsx +++ b/src/TabNavList/index.tsx @@ -51,9 +51,6 @@ export interface TabNavListProps { children?: (node: React.ReactElement) => React.ReactElement; getPopupContainer?: (node: HTMLElement) => HTMLElement; popupClassName?: string; - - /** @deprecated Use `indicator={ size: ... }` instead */ - indicatorSize?: GetIndicatorSize; indicator?: { size?: GetIndicatorSize; align?: 'start' | 'center' | 'end'; @@ -111,14 +108,9 @@ const TabNavList = React.forwardRef((props, ref children, onTabClick, onTabScroll, - indicatorSize, indicator, } = props; - const mergedIndicatorSize = indicator?.size || indicatorSize; - - const mergedIndicatorAlign = indicator?.align || 'center'; - const { prefixCls, tabs } = React.useContext(TabContext); const containerRef = useRef(null); const extraLeftRef = useRef(null); @@ -405,11 +397,8 @@ const TabNavList = React.forwardRef((props, ref const { style: indicatorStyle } = useIndicator({ activeTabOffset, horizontal: tabPositionTopOrBottom, + indicator, rtl, - indicator: { - size: mergedIndicatorSize, - align: mergedIndicatorAlign, - }, }); // ========================= Effect ======================== diff --git a/src/Tabs.tsx b/src/Tabs.tsx index d13e0479..3876e85e 100644 --- a/src/Tabs.tsx +++ b/src/Tabs.tsx @@ -67,11 +67,7 @@ export interface TabsProps moreIcon?: React.ReactNode; /** @private Internal usage. Not promise will rename in future */ moreTransitionName?: string; - popupClassName?: string; - - /** @deprecated Use `indicator={ size: ... }` instead */ - indicatorSize?: GetIndicatorSize; indicator?: { size?: GetIndicatorSize; align?: 'start' | 'center' | 'end'; @@ -103,7 +99,6 @@ const Tabs = React.forwardRef((props, ref) => { onTabScroll, getPopupContainer, popupClassName, - indicatorSize, indicator, ...restProps } = props; @@ -188,7 +183,6 @@ const Tabs = React.forwardRef((props, ref) => { panes: null, getPopupContainer, popupClassName, - indicatorSize, indicator, }; diff --git a/src/hooks/useIndicator.ts b/src/hooks/useIndicator.ts index 172bd523..4195c36f 100644 --- a/src/hooks/useIndicator.ts +++ b/src/hooks/useIndicator.ts @@ -15,21 +15,24 @@ interface UseIndicatorOptions { } const useIndicator = (options: UseIndicatorOptions) => { - const { activeTabOffset, horizontal, rtl, indicator } = options; + const { activeTabOffset, horizontal, rtl, indicator = {} } = options; + + const { size, align = 'center' } = indicator; + const [inkStyle, setInkStyle] = useState(); const inkBarRafRef = useRef(); const getLength = React.useCallback( (origin: number) => { - if (typeof indicator?.size === 'function') { - return indicator?.size(origin); + if (typeof size === 'function') { + return size(origin); } - if (typeof indicator?.size === 'number') { - return indicator?.size; + if (typeof size === 'number') { + return size; } return origin; }, - [indicator], + [size], ); // Delay set ink style to avoid remove tab blink @@ -44,27 +47,27 @@ const useIndicator = (options: UseIndicatorOptions) => { if (horizontal) { newInkStyle.width = getLength(activeTabOffset.width); const key = rtl ? 'right' : 'left'; - if (indicator?.align === 'start') { + if (align === 'start') { newInkStyle[key] = activeTabOffset[key]; } - if (indicator?.align === 'center') { + if (align === 'center') { newInkStyle[key] = activeTabOffset[key] + activeTabOffset.width / 2; newInkStyle.transform = rtl ? 'translateX(50%)' : 'translateX(-50%)'; } - if (indicator?.align === 'end') { + if (align === 'end') { newInkStyle[key] = activeTabOffset[key] + activeTabOffset.width; newInkStyle.transform = 'translateX(-100%)'; } } else { newInkStyle.height = getLength(activeTabOffset.height); - if (indicator?.align === 'start') { + if (align === 'start') { newInkStyle.top = activeTabOffset.top; } - if (indicator?.align === 'center') { + if (align === 'center') { newInkStyle.top = activeTabOffset.top + activeTabOffset.height / 2; newInkStyle.transform = 'translateY(-50%)'; } - if (indicator?.align === 'end') { + if (align === 'end') { newInkStyle.top = activeTabOffset.top + activeTabOffset.height; newInkStyle.transform = 'translateY(-100%)'; } @@ -77,7 +80,7 @@ const useIndicator = (options: UseIndicatorOptions) => { }); return cleanInkBarRaf; - }, [activeTabOffset, horizontal, rtl, indicator?.align, getLength]); + }, [activeTabOffset, horizontal, rtl, align, getLength]); return { style: inkStyle }; }; diff --git a/tests/index.test.tsx b/tests/index.test.tsx index d0f90698..bb377a73 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -630,11 +630,11 @@ describe('Tabs.Basic', () => { }); it('support indicatorSize', async () => { - const { container, rerender } = render(getTabs({ indicatorSize: 10 })); + const { container, rerender } = render(getTabs({ indicator: { size: 10 } })); await waitFakeTimer(); expect(container.querySelector('.rc-tabs-ink-bar')).toHaveStyle({ width: '10px' }); - rerender(getTabs({ indicatorSize: origin => origin - 2 })); + rerender(getTabs({ indicator: { size: origin => origin - 2 } })); await waitFakeTimer(); expect(container.querySelector('.rc-tabs-ink-bar')).toHaveStyle({ width: '18px' }); }); From a51fe43e89d1e35b9d195261a183080db6d80675 Mon Sep 17 00:00:00 2001 From: afc163 Date: Thu, 4 Jan 2024 23:23:32 +0800 Subject: [PATCH 35/65] 14.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3046a0d1..c73ce0c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-tabs", - "version": "13.0.0", + "version": "14.0.0", "description": "tabs ui component for react", "keywords": [ "react", From 9e0a4927893f583e2661a42e5e3f610f43b655af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 25 Feb 2024 20:48:23 +0800 Subject: [PATCH 36/65] chore(deps-dev): bump eslint-plugin-unicorn from 50.0.1 to 51.0.1 (#699) Bumps [eslint-plugin-unicorn](/~https://github.com/sindresorhus/eslint-plugin-unicorn) from 50.0.1 to 51.0.1. - [Release notes](/~https://github.com/sindresorhus/eslint-plugin-unicorn/releases) - [Commits](/~https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v50.0.1...v51.0.1) --- updated-dependencies: - dependency-name: eslint-plugin-unicorn dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c73ce0c1..6386d44b 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "dumi": "^2.0.0", "eslint": "^8.54.0", "eslint-plugin-jest": "^27.6.0", - "eslint-plugin-unicorn": "^50.0.1", + "eslint-plugin-unicorn": "^51.0.1", "fastclick": "~1.0.6", "father": "^4.0.0", "gh-pages": "^6.1.0", From ab106a3505cf23d53bdd24dcf6d2b2542cfe71c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E7=88=B1=E5=90=83=E7=99=BD=E8=90=9D?= =?UTF-8?q?=E5=8D=9C?= Date: Fri, 8 Mar 2024 14:23:07 +0800 Subject: [PATCH 37/65] chore: bump menu (#702) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6386d44b..9cead2ae 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@babel/runtime": "^7.11.2", "classnames": "2.x", "rc-dropdown": "~4.1.0", - "rc-menu": "~9.12.0", + "rc-menu": "~9.13.0", "rc-motion": "^2.6.2", "rc-resize-observer": "^1.0.0", "rc-util": "^5.34.1" From d07058d49a79c359a22db3f5f98dee9bff6306c6 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: Fri, 8 Mar 2024 14:27:04 +0800 Subject: [PATCH 38/65] 14.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9cead2ae..a0991d84 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-tabs", - "version": "14.0.0", + "version": "14.1.0", "description": "tabs ui component for react", "keywords": [ "react", From 5a134edb7bc6d06d6bc07c6e0e120d74cf8a25e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E7=88=B1=E5=90=83=E7=99=BD=E8=90=9D?= =?UTF-8?q?=E5=8D=9C?= Date: Fri, 8 Mar 2024 15:31:44 +0800 Subject: [PATCH 39/65] chore: bump dropdown (#703) --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a0991d84..cdf94696 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "dependencies": { "@babel/runtime": "^7.11.2", "classnames": "2.x", - "rc-dropdown": "~4.1.0", + "rc-dropdown": "~4.2.0", "rc-menu": "~9.13.0", "rc-motion": "^2.6.2", "rc-resize-observer": "^1.0.0", @@ -47,7 +47,7 @@ }, "devDependencies": { "@rc-component/father-plugin": "^1.0.0", - "@rc-component/trigger": "^1.10.0", + "@rc-component/trigger": "^2.0.0", "@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "^14.1.2", "@types/classnames": "^2.2.10", From afadb057c9a96d46fefc09599856e121d0ebcd52 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: Fri, 8 Mar 2024 15:34:26 +0800 Subject: [PATCH 40/65] 14.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cdf94696..1111db8d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-tabs", - "version": "14.1.0", + "version": "14.1.1", "description": "tabs ui component for react", "keywords": [ "react", From 631a5b1b1eb0f7cc93820d2e8f9a243d9fc43b81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 31 Mar 2024 20:31:34 +0800 Subject: [PATCH 41/65] chore(deps-dev): bump np from 9.2.0 to 10.0.2 (#705) Bumps [np](/~https://github.com/sindresorhus/np) from 9.2.0 to 10.0.2. - [Release notes](/~https://github.com/sindresorhus/np/releases) - [Commits](/~https://github.com/sindresorhus/np/compare/v9.2.0...v10.0.2) --- updated-dependencies: - dependency-name: np dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1111db8d..0f91f621 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "history": "^5.3.0", "immutability-helper": "^3.0.1", "less": "^4.1.3", - "np": "^9.0.0", + "np": "^10.0.2", "preact-compat": "^3.16.0", "rc-test": "^7.0.14", "react": "^18.0.0", From 43e78d8b246222316812688efdcfbdd4115ec9f4 Mon Sep 17 00:00:00 2001 From: Cooper <73218815+CooperHash@users.noreply.github.com> Date: Fri, 5 Apr 2024 21:42:09 +0800 Subject: [PATCH 42/65] feat: add overflow trigger props (#706) * feat: add overflow trigger props * combine moreTrigger and moreIcon to more props * Optimization Type * add dropdownprops with omit children * merge moreTransitio to more * fix * fix * remove moreTransition --- src/TabNavList/OperationNode.tsx | 13 ++++++------- src/TabNavList/index.tsx | 4 ++-- src/Tabs.tsx | 10 ++++------ src/interface.ts | 12 ++++++++++-- tests/overflow.test.tsx | 18 ++++++++++++++++++ 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/TabNavList/OperationNode.tsx b/src/TabNavList/OperationNode.tsx index bb71adf6..972da8fd 100644 --- a/src/TabNavList/OperationNode.tsx +++ b/src/TabNavList/OperationNode.tsx @@ -4,7 +4,7 @@ import Menu, { MenuItem } from 'rc-menu'; import KeyCode from 'rc-util/lib/KeyCode'; import * as React from 'react'; import { useEffect, useState } from 'react'; -import type { EditableConfig, Tab, TabsLocale } from '../interface'; +import type { EditableConfig, Tab, TabsLocale, MoreProps } from '../interface'; import { getRemovable } from '../util'; import AddButton from './AddButton'; @@ -18,8 +18,7 @@ export interface OperationNodeProps { tabBarGutter?: number; activeKey: string; mobile: boolean; - moreIcon?: React.ReactNode; - moreTransitionName?: string; + more?: MoreProps; editable?: EditableConfig; locale?: TabsLocale; removeAriaLabel?: string; @@ -36,8 +35,7 @@ const OperationNode = React.forwardRef((prop tabs, locale, mobile, - moreIcon = 'More', - moreTransitionName, + more: moreProps = {}, style, className, editable, @@ -52,6 +50,8 @@ const OperationNode = React.forwardRef((prop const [open, setOpen] = useState(false); const [selectedKey, setSelectedKey] = useState(null); + const { icon: moreIcon = 'More' } = moreProps; + const popupId = `${id}-more-popup`; const dropdownPrefix = `${prefixCls}-dropdown`; const selectedItemId = selectedKey !== null ? `${popupId}-${selectedKey}` : null; @@ -190,14 +190,13 @@ const OperationNode = React.forwardRef((prop