From d124a629116570d41d83348058ee0f98f310f55b 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: Wed, 3 Jun 2020 15:25:51 +0800 Subject: [PATCH] refactor: TabPane is a element (#279) * refactor: TabPane is a element * clean up --- src/TabPanelList/TabPane.tsx | 31 +++++-- src/TabPanelList/index.tsx | 21 ++--- src/Tabs.tsx | 26 +++--- src/index.ts | 4 +- src/interface.ts | 6 +- src/sugar/TabPane.tsx | 17 ---- tests/__snapshots__/index.test.tsx.snap | 98 ++++++++++++++++++---- tests/__snapshots__/overflow.test.tsx.snap | 4 +- tests/__snapshots__/suger.test.tsx.snap | 3 - tests/index.test.tsx | 16 ++++ tests/suger.test.tsx | 9 -- 11 files changed, 153 insertions(+), 82 deletions(-) delete mode 100644 src/sugar/TabPane.tsx delete mode 100644 tests/__snapshots__/suger.test.tsx.snap delete mode 100644 tests/suger.test.tsx diff --git a/src/TabPanelList/TabPane.tsx b/src/TabPanelList/TabPane.tsx index 4687fd9b..6efa9b72 100644 --- a/src/TabPanelList/TabPane.tsx +++ b/src/TabPanelList/TabPane.tsx @@ -1,23 +1,36 @@ import * as React from 'react'; import classNames from 'classnames'; -import { Tab } from '../interface'; export interface TabPaneProps { - prefixCls: string; - id: string; - tab: Tab; - animated: boolean; - active: boolean; + tab?: React.ReactNode; + className?: string; + style?: React.CSSProperties; + disabled?: boolean; + children?: React.ReactNode; + forceRender?: boolean; + closable?: boolean; + closeIcon?: React.ReactNode; + + // Pass by TabPaneList + prefixCls?: string; + tabKey?: string; + id?: string; + animated?: boolean; + active?: boolean; destroyInactiveTabPane?: boolean; } export default function TabPane({ prefixCls, + forceRender, + className, + style, id, active, animated, destroyInactiveTabPane, - tab: { key, children, forceRender, className, style }, + tabKey, + children, }: TabPaneProps) { const [visited, setVisited] = React.useState(forceRender); @@ -40,10 +53,10 @@ export default function TabPane({ return (
{tabs.map(tab => { - return ( - - ); + return React.cloneElement(tab.node, { + key: tab.key, + prefixCls, + tabKey: tab.key, + id, + animated: tabPaneAnimated, + active: tab.key === activeKey, + destroyInactiveTabPane, + }); })}
diff --git a/src/Tabs.tsx b/src/Tabs.tsx index cff81245..c0b720a5 100644 --- a/src/Tabs.tsx +++ b/src/Tabs.tsx @@ -4,17 +4,17 @@ import { useEffect, useState } from 'react'; import classNames from 'classnames'; import toArray from 'rc-util/lib/Children/toArray'; import useMergedState from 'rc-util/lib/hooks/useMergedState'; -import TabPane, { TabPaneProps } from './sugar/TabPane'; import TabNavList from './TabNavList'; import TabPanelList from './TabPanelList'; +import TabPane, { TabPaneProps } from './TabPanelList/TabPane'; import { - Tab, TabPosition, RenderTabBar, TabsLocale, EditableConfig, AnimatedConfig, OnTabScroll, + Tab, } from './interface'; import TabContext from './TabContext'; import { isMobile } from './hooks/useTouchMove'; @@ -66,14 +66,20 @@ export interface TabsProps extends Omit, 'o } function parseTabList(children: React.ReactNode): Tab[] { - return toArray(children).map((node: React.ReactElement) => - React.isValidElement(node) - ? { - key: node.key !== undefined ? String(node.key) : undefined, + return toArray(children) + .map((node: React.ReactElement) => { + if (React.isValidElement(node)) { + const key = node.key !== undefined ? String(node.key) : undefined; + return { + key, ...node.props, - } - : null, - ); + node, + }; + } + + return null; + }) + .filter(tab => tab); } function Tabs( @@ -156,7 +162,7 @@ function Tabs( // Async generate id to avoid ssr mapping failed useEffect(() => { if (!id) { - setMergedId(`rc-tabs-${uuid}`); + setMergedId(`rc-tabs-${process.env.NODE_ENV === 'test' ? 'test' : uuid}`); uuid += 1; } }, []); diff --git a/src/index.ts b/src/index.ts index 7a761ac5..917fb678 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import Tabs, { TabsProps } from './Tabs'; -import TabPane from './sugar/TabPane'; +import TabPane, { TabPaneProps } from './TabPanelList/TabPane'; -export { TabPane, TabsProps }; +export { TabPane, TabsProps, TabPaneProps }; export default Tabs; diff --git a/src/interface.ts b/src/interface.ts index 8f5c5d8a..f3da6014 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -1,4 +1,4 @@ -import { TabPaneProps } from './sugar/TabPane'; +import { TabPaneProps } from './TabPanelList/TabPane'; export type TabSizeMap = Map< React.Key, @@ -17,10 +17,8 @@ export type TabOffsetMap = Map; export type TabPosition = 'left' | 'right' | 'top' | 'bottom'; export interface Tab extends TabPaneProps { - tab?: React.ReactNode; - children?: React.ReactNode; - forceRender?: boolean; key: string; + node: React.ReactElement; } export type RenderTabBar = (props: any, DefaultTabBar: React.ComponentType) => React.ReactElement; diff --git a/src/sugar/TabPane.tsx b/src/sugar/TabPane.tsx deleted file mode 100644 index 8dc928ca..00000000 --- a/src/sugar/TabPane.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import * as React from 'react'; - -export interface TabPaneProps { - tab?: React.ReactNode; - className?: string; - style?: React.CSSProperties; - disabled?: boolean; - children?: React.ReactNode; - forceRender?: boolean; - closable?: boolean; - closeIcon?: React.ReactNode; -} - -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export default function TabPane(_: TabPaneProps) { - return null; -} diff --git a/tests/__snapshots__/index.test.tsx.snap b/tests/__snapshots__/index.test.tsx.snap index 9ee31558..43335b17 100644 --- a/tests/__snapshots__/index.test.tsx.snap +++ b/tests/__snapshots__/index.test.tsx.snap @@ -16,10 +16,10 @@ exports[`Tabs.Basic Normal 1`] = ` style="transform: translate(0px, 0px);" > +
+
+ +
+ +
+ +
+
+
+ Light +
+
+
+ +`; diff --git a/tests/__snapshots__/overflow.test.tsx.snap b/tests/__snapshots__/overflow.test.tsx.snap index 07e8d171..759e5637 100644 --- a/tests/__snapshots__/overflow.test.tsx.snap +++ b/tests/__snapshots__/overflow.test.tsx.snap @@ -2,12 +2,12 @@ exports[`Tabs.Overflow should collapse 1`] = `