From 62d68b049f884840633722e51345bfd5da8e0ad0 Mon Sep 17 00:00:00 2001 From: mushan0x0 Date: Tue, 28 Aug 2018 18:56:25 +0800 Subject: [PATCH] feat: Tabs render tab bar (#11856) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Customized bar of tab. * docs: 更新关于renderTabBar的中文文档 * docs: 更新关于renderTabBar的英文文档 * update: 优化代码 * docs: 更新关于renderTabBar的文档 * update: 完善renderTabBar代码 * update: 完成自定义tabBar * docs: 去掉旧的DefaultTabBar参数说明 * update: 修复CI测试 * fix: 去掉>选择器,解决自定义tabBar后样式错误 * update: 优化代码质量 * update: 添加测试 * fix: lint * fix: 避免tab嵌套bug * update: 把DefaultTabBar放在renderTabBar里 --- .../__tests__/__snapshots__/demo.test.js.snap | 4 +- components/tabs/TabBar.tsx | 51 +++++++ .../__tests__/__snapshots__/demo.test.js.snap | 139 ++++++++++++++++++ .../__snapshots__/index.test.js.snap | 22 +++ components/tabs/__tests__/index.test.js | 11 ++ components/tabs/demo/custom-tab-bar.md | 39 +++++ components/tabs/index.en-US.md | 1 + components/tabs/index.tsx | 61 ++------ components/tabs/index.zh-CN.md | 1 + package.json | 1 + 10 files changed, 279 insertions(+), 51 deletions(-) create mode 100644 components/tabs/TabBar.tsx create mode 100644 components/tabs/demo/custom-tab-bar.md diff --git a/components/card/__tests__/__snapshots__/demo.test.js.snap b/components/card/__tests__/__snapshots__/demo.test.js.snap index 62e9666410..304f9d17b7 100644 --- a/components/card/__tests__/__snapshots__/demo.test.js.snap +++ b/components/card/__tests__/__snapshots__/demo.test.js.snap @@ -674,7 +674,7 @@ exports[`renders ./components/card/demo/tabs.md correctly 1`] = ` class="ant-tabs ant-tabs-top ant-card-head-tabs ant-tabs-large ant-tabs-line" >
@@ -809,7 +809,7 @@ exports[`renders ./components/card/demo/tabs.md correctly 1`] = ` class="ant-tabs ant-tabs-top ant-card-head-tabs ant-tabs-large ant-tabs-line" >
diff --git a/components/tabs/TabBar.tsx b/components/tabs/TabBar.tsx new file mode 100644 index 0000000000..76d22a9da5 --- /dev/null +++ b/components/tabs/TabBar.tsx @@ -0,0 +1,51 @@ +import * as React from 'react'; +import Icon from '../icon'; +import ScrollableInkTabBar from 'rc-tabs/lib/ScrollableInkTabBar'; +import { TabsProps } from './index'; + +export default class TabBar extends React.Component { + render() { + const { + tabBarStyle, + animated = true, + renderTabBar, + tabBarExtraContent, + tabPosition, + prefixCls, + } = this.props; + const inkBarAnimated = typeof animated === 'object' ? animated.inkBar : animated; + + const isVertical = tabPosition === 'left' || tabPosition === 'right'; + const prevIconType = isVertical ? 'up' : 'left'; + const nextIconType = isVertical ? 'down' : 'right'; + const prevIcon = ( + + + + ); + const nextIcon = ( + + + + ); + + const renderProps = { + ...this.props, + inkBarAnimated, + extraContent: tabBarExtraContent, + style: tabBarStyle, + prevIcon, + nextIcon, + }; + + let RenderTabBar: React.ReactElement; + + if (renderTabBar) { + RenderTabBar = renderTabBar(renderProps, ScrollableInkTabBar); + } else { + RenderTabBar = ; + } + + return React.cloneElement(RenderTabBar); + } +} diff --git a/components/tabs/__tests__/__snapshots__/demo.test.js.snap b/components/tabs/__tests__/__snapshots__/demo.test.js.snap index d3fa6d0f20..4c6d7b7488 100644 --- a/components/tabs/__tests__/__snapshots__/demo.test.js.snap +++ b/components/tabs/__tests__/__snapshots__/demo.test.js.snap @@ -576,6 +576,145 @@ exports[`renders ./components/tabs/demo/custom-add-trigger.md correctly 1`] = `
`; +exports[`renders ./components/tabs/demo/custom-tab-bar.md correctly 1`] = ` +
+
+
+
+
+
+ + + + + + + + + + + + + + +
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+ Content of Tab Pane 1 +
+ +
+`; + exports[`renders ./components/tabs/demo/disabled.md correctly 1`] = `
+
+ custom-tab-bar +
+
+
+ foo +
+
+
+`; + exports[`Tabs tabPosition remove card 1`] = `
{ expect(wrapper).toMatchSnapshot(); }); }); + + describe('renderTabBar', () => { + it('custom-tab-bar', () => { + const wrapper = render( +
custom-tab-bar
}> + foo +
+ ); + expect(wrapper).toMatchSnapshot(); + }); + }); }); diff --git a/components/tabs/demo/custom-tab-bar.md b/components/tabs/demo/custom-tab-bar.md new file mode 100644 index 0000000000..ebeb286a43 --- /dev/null +++ b/components/tabs/demo/custom-tab-bar.md @@ -0,0 +1,39 @@ +--- +order: 12 +title: + zh-CN: 自定义页签头 + en-US: Customized bar of tab +--- + +## zh-CN + +使用 react-sticky 组件实现吸顶效果。 + +## en-US + +use react-sticky. + +````jsx +import { Tabs } from 'antd'; +import { StickyContainer, Sticky } from 'react-sticky'; + +const TabPane = Tabs.TabPane; + +const renderTabBar = (props, DefaultTabBar) => ( + + {({ style }) => ( + + )} + +); + +ReactDOM.render( + + + Content of Tab Pane 1 + Content of Tab Pane 2 + Content of Tab Pane 3 + + , + mountNode); +```` diff --git a/components/tabs/index.en-US.md b/components/tabs/index.en-US.md index b5a5993ef2..e0dfcd57e6 100644 --- a/components/tabs/index.en-US.md +++ b/components/tabs/index.en-US.md @@ -23,6 +23,7 @@ Ant Design has 3 types of Tabs for different situations. | -------- | ----------- | ---- | ------- | | activeKey | Current TabPane's key | string | - | | animated | Whether to change tabs with animation. Only works while `tabPosition="top"\|"bottom"` | boolean \| {inkBar:boolean, tabPane:boolean} | `true`, `false` when `type="card"` | +| renderTabBar | replace the TabBar | (props: DefaultTabBarProps, DefaultTabBar: React.ReactNode) => React.ReactNode | - | | defaultActiveKey | Initial active TabPane's key, if `activeKey` is not set. | string | - | | hideAdd | Hide plus icon or not. Only works while `type="editable-card"` | boolean | `false` | | size | preset tab bar size | `large` \| `default` \| `small` | `default` | diff --git a/components/tabs/index.tsx b/components/tabs/index.tsx index db56320778..5fc911febc 100755 --- a/components/tabs/index.tsx +++ b/components/tabs/index.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import RcTabs, { TabPane } from 'rc-tabs'; -import ScrollableInkTabBar from 'rc-tabs/lib/ScrollableInkTabBar'; import TabContent from 'rc-tabs/lib/TabContent'; +import TabBar from './TabBar'; import classNames from 'classnames'; import Icon from '../icon'; import warning from '../_util/warning'; @@ -30,6 +30,7 @@ export interface TabsProps { className?: string; animated?: boolean | { inkBar: boolean; tabPane: boolean; }; tabBarGutter?: number; + renderTabBar?: (props: TabsProps, DefaultTabBar: React.ReactNode) => React.ReactElement; } // Tabs @@ -51,13 +52,6 @@ export default class Tabs extends React.Component { hideAdd: false, }; - createNewTab = (targetKey: React.MouseEvent) => { - const onEdit = this.props.onEdit; - if (onEdit) { - onEdit(targetKey, 'add'); - } - } - removeTab = (targetKey: string, e: React.MouseEvent) => { e.stopPropagation(); if (!targetKey) { @@ -77,6 +71,13 @@ export default class Tabs extends React.Component { } } + createNewTab = (targetKey: React.MouseEvent) => { + const { onEdit } = this.props; + if (onEdit) { + onEdit(targetKey, 'add'); + } + } + componentDidMount() { const NO_FLEX = ' no-flex'; const tabNode = ReactDOM.findDOMNode(this) as Element; @@ -93,21 +94,12 @@ export default class Tabs extends React.Component { type = 'line', tabPosition, children, + animated = true, tabBarExtraContent, - tabBarStyle, hideAdd, - onTabClick, - onPrevClick, - onNextClick, - animated = true, - tabBarGutter, } = this.props; - let { inkBarAnimated, tabPaneAnimated } = typeof animated === 'object' ? { - inkBarAnimated: animated.inkBar, tabPaneAnimated: animated.tabPane, - } : { - inkBarAnimated: animated, tabPaneAnimated: animated, - }; + let tabPaneAnimated = typeof animated === 'object' ? animated.tabPane : animated; // card tabs should not have animation if (type !== 'line') { @@ -166,41 +158,12 @@ export default class Tabs extends React.Component {
) : null; - const renderTabBar = () => { - const isVertical = tabPosition === 'left' || tabPosition === 'right'; - const prevIconType = isVertical ? 'up' : 'left'; - const nextIconType = isVertical ? 'down' : 'right'; - const prevIcon = ( - - - - ); - const nextIcon = ( - - - - ); - return ( - - ); - }; - return ( } renderTabContent={() => } onChange={this.handleChange} > diff --git a/components/tabs/index.zh-CN.md b/components/tabs/index.zh-CN.md index c4eff58f21..10522b44d4 100644 --- a/components/tabs/index.zh-CN.md +++ b/components/tabs/index.zh-CN.md @@ -26,6 +26,7 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。 | --- | --- | --- | --- | | activeKey | 当前激活 tab 面板的 key | string | 无 | | animated | 是否使用动画切换 Tabs,在 `tabPosition=top|bottom` 时有效 | boolean \| {inkBar:boolean, tabPane:boolean} | true, 当 type="card" 时为 false | +| renderTabBar | 替换TabBar,用于二次封装标签头 | (props: DefaultTabBarProps, DefaultTabBar: React.ReactNode) => React.ReactNode | 无 | | defaultActiveKey | 初始化选中面板的 key,如果没有设置 activeKey | string | 第一个面板 | | hideAdd | 是否隐藏加号图标,在 `type="editable-card"` 时有效 | boolean | false | | size | 大小,提供 `large` `default` 和 `small` 三种大小 | string | 'default' | diff --git a/package.json b/package.json index c7e273f3aa..e4ef0c5fa7 100644 --- a/package.json +++ b/package.json @@ -164,6 +164,7 @@ "react-intl": "^2.0.1", "react-resizable": "^1.7.5", "react-router-dom": "^4.2.2", + "react-sticky": "^6.0.3", "react-sublime-video": "^0.2.0", "react-virtualized": "~9.20.0", "remark-frontmatter": "^1.1.0",