Skip to content

Commit

Permalink
feat(design): Tabs items and TabPane add divider prop
Browse files Browse the repository at this point in the history
  • Loading branch information
dengfuping committed Jul 26, 2024
1 parent 2268cf6 commit 7b69780
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 35 deletions.
1 change: 1 addition & 0 deletions packages/design/src/tabs/TabPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type React from 'react';

export interface TabPaneProps extends AntTabPaneProps {
tag?: React.ReactNode;
divider?: boolean;
}

export default AntTabs.TabPane as React.FC<TabPaneProps>;
40 changes: 40 additions & 0 deletions packages/design/src/tabs/demo/divider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { TabsProps } from '@oceanbase/design';
import { Space, Tabs } from '@oceanbase/design';
import React from 'react';

const onChange = (key: string) => {
console.log(key);
};

const items: TabsProps['items'] = [
{
key: '1',
label: `Tab 1`,
children: `Content of Tab Pane 1`,
},
{
divider: true,
},
{
key: '2',
label: `Tab 2`,
children: `Content of Tab Pane 2`,
},
{
divider: true,
},
{
key: '3',
label: `Tab 3`,
children: `Content of Tab Pane 3`,
},
];

const App: React.FC = () => (
<Space direction="vertical" size={32}>
<Tabs defaultActiveKey="1" items={items} onChange={onChange} />
<Tabs defaultActiveKey="1" items={items} tabPosition="left" onChange={onChange} />
</Space>
);

export default App;
2 changes: 2 additions & 0 deletions packages/design/src/tabs/demo/tab-pane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ const App: React.FC = () => {
<Tabs.TabPane key="1" tab="Tab 1" tag={22}>
Content of Tab Pane 1
</Tabs.TabPane>
<Tabs.TabPane divider={true} />
<Tabs.TabPane key="2" tab="Tab 2" tag={99}>
Content of Tab Pane 2
</Tabs.TabPane>
<Tabs.TabPane divider={true} />
<Tabs.TabPane key="3" tab="Tab 3" tag={0}>
Content of Tab Pane 3
</Tabs.TabPane>
Expand Down
26 changes: 5 additions & 21 deletions packages/design/src/tabs/hooks/useLegacyItems.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
import { isNullValue } from '@oceanbase/util';
import { Space, Tag } from 'antd';
import warning from 'antd/es/_util/warning';
import type { Tab } from 'rc-tabs/lib/interface';
import toArray from 'rc-util/lib/Children/toArray';
import * as React from 'react';
import type { TabsProps } from '..';
import type { TabsProps, Tab } from '..';
import type { TabPaneProps } from '../TabPane';

function filter<T>(items: (T | null)[]): T[] {
return items.filter(item => item) as T[];
}

// ref: https://github.com/ant-design/ant-design/blob/master/components/tabs/hooks/useLegacyItems.ts
export default function useLegacyItems(
items?: TabsProps['items'],
children?: React.ReactNode,
prefixCls?: string
) {
export default function useLegacyItems(items?: TabsProps['items'], children?: React.ReactNode) {
if (items) {
return items;
}
Expand All @@ -26,21 +19,12 @@ export default function useLegacyItems(
const childrenItems = toArray(children).map((node: React.ReactElement<TabPaneProps>) => {
if (React.isValidElement(node)) {
const { key, props } = node;
const { tab, tag, ...restProps } = props || {};
const { tab, ...restProps } = props || {};

const item: Tab = {
key,
key: key as string,
...restProps,
label: isNullValue(tag) ? (
tab
) : (
<Space size={4}>
{tab}
<Tag bordered={false} className={`${prefixCls}-tab-tag`}>
{tag}
</Tag>
</Space>
),
label: tab,
};
return item;
}
Expand Down
10 changes: 7 additions & 3 deletions packages/design/src/tabs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ nav:
- 🔥 完全继承 antd [Tabs](https://ant.design/components/tabs-cn) 的能力和 API,可无缝切换。
- 💄 定制主题和样式(火柴棍宽度等),符合 OceanBase Design 设计规范。
- 🆕 `items``TabPane` 新增 `tag` 属性,用于设置选项卡后面的标签。
- 🆕 `items``TabPane` 新增 `divider` 属性,用于设置选项卡为分割线。

## 代码演示

Expand All @@ -17,6 +18,8 @@ nav:

<code src="./demo/position.tsx" title="位置"></code>

<code src="./demo/divider.tsx" title="分割线"></code>

<code src="./demo/tag.tsx" title="标签" description="可设置选项卡后面的标签"></code>

<code src="./demo/tab-pane.tsx" title="TabPane 语法糖(不推荐使用)" description="即将废弃的 API,不推荐使用,详见 antd [文档](https://4x.ant.design/components/tabs-cn/#4.23.0-%E7%94%A8%E6%B3%95%E5%8D%87%E7%BA%A7)"></code>
Expand All @@ -25,8 +28,9 @@ nav:

### items

| 参数 | 说明 | 类型 | 默认值 | 版本 |
| :--- | :----------------------- | :-------- | :----- | :--- |
| tag | 用于设置选项卡后面的标签 | ReactNode | - | - |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| :------ | :----------------------- | :-------- | :----- | :--- |
| tag | 用于设置选项卡后面的标签 | ReactNode | - | - |
| divider | 用于设置选项卡为分割线 | boolean | - | - |

- 更多 API 详见 antd Tabs 文档: https://ant.design/components/tabs-cn
40 changes: 30 additions & 10 deletions packages/design/src/tabs/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isNullValue } from '@oceanbase/util';
import { Space, Tabs as AntTabs, Tag } from 'antd';
import { Divider, Space, Tabs as AntTabs, Tag } from 'antd';
import React, { useContext } from 'react';
import type { TabsProps as AntTabsProps, TabsPosition as AntTabsPosition } from 'antd/es/tabs';
import type { Tab as AntTab } from 'rc-tabs/es/interface';
Expand All @@ -8,16 +8,22 @@ import ConfigProvider from '../config-provider';
import useLegacyItems from './hooks/useLegacyItems';
import useStyle from './style';
import TabPane from './TabPane';
import type { TabPaneProps } from './TabPane';

export * from 'antd/es/tabs';
export type { TabPaneProps };

export type { TabPaneProps } from './TabPane';
export interface AntTabOptional extends Omit<AntTab, 'key' | 'label'> {
key?: string;
label?: React.ReactNode;
}

export interface Tab extends AntTab {
export type Tab = {
tag?: React.ReactNode;
}
divider?: boolean;
} & (AntTab | AntTabOptional);

export interface TabsProps extends AntTabsProps {
export interface TabsProps extends Omit<AntTabsProps, 'items'> {
items?: Tab[];
}

Expand All @@ -38,9 +44,25 @@ const Tabs = ({
const tabsCls = classNames(className);

const isHorizontal = !tabPosition || tabPosition === 'top' || tabPosition === 'bottom';
const dividerList = items?.filter(item => item.divider) || [];

let newItems = useLegacyItems(items, children);

let newItems = items?.map(item => {
if (!isNullValue(item.tag)) {
newItems = newItems?.map(item => {
if (!isNullValue(item.divider)) {
return {
...item,
key: `divider-${dividerList?.indexOf(item)}`,
label: (
<Divider
// horizontal tabs => vertical divider
type={isHorizontal ? 'vertical' : 'horizontal'}
className={`${prefixCls}-divider`}
/>
),
disabled: true,
};
} else if (!isNullValue(item.tag)) {
return {
...item,
label: (
Expand All @@ -56,11 +78,9 @@ const Tabs = ({
return item;
});

newItems = useLegacyItems(newItems, children, prefixCls);

return wrapSSR(
<AntTabs
items={newItems}
items={newItems as AntTabsProps['items']}
type={type}
tabPosition={tabPosition}
tabBarGutter={!type || type === 'line' ? (isHorizontal ? 24 : 0) : undefined}
Expand Down
18 changes: 17 additions & 1 deletion packages/design/src/tabs/style/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type CardToken = FullToken<'Card'>;
export const genTagStyle: GenerateStyle<TabsToken | CardToken> = (
token: TabsToken | CardToken
): CSSObject => {
const { componentCls, colorInfo, colorInfoBg, colorTextSecondary } = token;
const { antCls, componentCls, colorInfo, colorInfoBg, colorTextSecondary } = token;
return {
[componentCls]: {
[`&${componentCls}-top, &${componentCls}-bottom`]: {
Expand All @@ -33,6 +33,22 @@ export const genTagStyle: GenerateStyle<TabsToken | CardToken> = (
backgroundColor: colorInfoBg,
},
},
[`${componentCls}-tab[data-node-key^=divider-]`]: {
cursor: 'default',
[`${componentCls}-tab-btn`]: {
// make horizontal divider width 100% work
width: '100%',
[`${componentCls}-divider`]: {
margin: 0,
[`&${antCls}-divider-vertical`]: {
height: token.sizeMD,
},
[`&${antCls}-divider-horizontal`]: {
width: '100%',
},
},
},
},
[`${componentCls}-ink-bar`]: {
// inkbar 带圆角
borderRadius: '1px',
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"esModuleInterop": true,
"types": ["node", "vitest/globals"],
"declaration": true,
"strict": true,
// TS 编译时跳过对 node_modules 依赖的检查
"skipLibCheck": true,
"resolveJsonModule": true,
Expand Down

0 comments on commit 7b69780

Please sign in to comment.